วิธีการกำหนดค่าตัวแปรของคลาสแบบไดนามิกใน TypeScript
ฉันต้องการมอบหมายคุณสมบัติหลายอย่างให้กับ MyClass ใน TypeScript แบบไดนามิกเพื่อไม่จำเป็นต้องเขียนหลายบรรทัดของโค้ดสำหรับการตั้งค่าคุณสมบัติของคลาส ฉันเขียนโค้ดดังต่อไปนี้:
interface IMy
{
visible?: boolean;
text?: string;
}
class MyClass
{
element: JQuery;
assing(o: IMy): void
{
for (let [key, value] of Object.entries(o))
{
if (typeof value !== "undefined")
this[key] = value;
}
}
get visible(): boolean
{
return this.element.is(":visible");
}
set visible(visible: boolean)
{
this.element.css("display", visible ? "" : "none");
}
get text(): string
{
return this.element.html();
}
set text(text: string)
{
this.element.html(text);
}
}
let t = new MyClass();
t.assign({ visible: true });
//instead t.visible = true;
//or
t.assign({ text: "Something" });
//instead t.text = "something";
//or
t.assign({ text: "Something", visible: false });
//instead t.visible = true;
// t.text = "something";
แต่ฉันมีปัญหาในบรรทัด this[key]=value; พร้อมกับข้อผิดพลาด:
ลายเซ็นดัชนีของประเภทวัตถุมีประเภท 'any' โดยปริยาย
สิ่งที่ฉันจำเป็นต้องเปลี่ยนหรือแนวทางของฉันผิดพลาดทั้งหมดหรือไม่?
มันยังจะเป็นวิธีแก้ปัญหาที่ดีสำหรับการตั้งค่าคุณสมบัติปริยายในคอนสตรัคเตอร์เมื่ออินเทอร์เฟซเป็นพารามิเตอร์ของคอนสตรัคเตอร์
แก้ไขแล้ว:
เกี่ยวกับรายการ ฉันชอบมันจริงๆ ดังนั้นฉันจึงใช้โค้ดนี้:
//extensions.d.ts
interface Object
{
entries<T>(o: any): [string, T][];
entries(o: any): [string, any][];
}
//exntesion.js !!note js not ts
if (!Object.entries)
{
Object.entries = function* entries(obj)
{
for (let key of Object.keys(obj))
{
yield [key, obj[key]];
}
};
}
แก้ไข 2:
แนวคิดหลักคือการแก้ปัญหาสำหรับการสร้างคอนสตรัคเตอร์ที่มีการโอเวอร์โหลดซึ่งคุณสามารถตั้งค่าเฉพาะคุณสมบัติที่ต้องการได้
นี่คือโค้ดทั้งหมดหากมีคนอื่นพบว่ามันใช้งานได้
interface IMy
{
prop1?: boolean;
prop2?: string;
prop3?: string;
prop4?: number;
}
class MyClass implements IMy
{
prop1: boolean = false;
prop2: string = "";
prop3: string = "Something";
prop4: number = 0;
constructor(properties: IMy)
{
this.assing(properties);
}
assing(o: IMy): void
{
let that = (<any>this);
for (let key in o)
{
if (o.hasOwnProperty(key))
{
let value = (<any>o)[key];
if (typeof value !== "undefined" && typeof that[key] !== "undefined")
that[key] = value;
}
}
}
}
let my1 = new MyClass({ prop1: true });
let my2 = new MyClass({ prop2: "SomeText", prop3: "Anything" });
//I set prop2 and prop3
let my3 = new MyClass({ prop4: 10 });
//I set prop4 (fourth parameter)
console.log(my1, my2, my3);
คำตอบ #1
ข้อผิดพลาดมาจากตัวเลือกคอมไพเลอร์ --noImplicitAny หากคุณลบมัน ข้อผิดพลาดก็จะหายไป แต่ผมเชื่อและมันไม่ใช่สิ่งเลวร้ายที่จะมี
คุณจะต้องเพิ่มคำอธิบายประเภทให้กับ key ซึ่งดูเหมือนไม่เป็นปัญหาเมื่ออยู่ในลูป for .. of
ฉันคิดว่าการดำเนินการนี้ไม่ได้แย่ แต่คุณจะต้องเขียนใหม่การวนซ้ำผ่านคุณสมบัติบางอย่างต่างออกไปเล็กน้อย
แค่ขอเสริมไปอีกอย่าง ผมสมมติว่าคุณก็กำลังตั้งเป้าไปที่ ES6 ด้วย (เพื่อให้คอมไพเลอร์ไม่บ่นเรื่อง .entries() ซึ่งดูเหมือนเป็นฟีเจอร์ของ ES6 มันดูเหมือนจะใช้กับอาเรย์ ไม่ใช่วัตถุ
แก้ไข :
ได้รับแรงบันดาลใจจากคำตอบของ SO อื่น ๆ - เพื่อให้ข้อผิดพลาดหายไป คุณสามารถเพิ่มการแปลงชนิดเป็น any ดังนี้:
(<any>this)[key] = value;
ข้อข้างต้นเกี่ยวกับการใช้ .entries() ยังคงใช้ได้อยู่เหมือนเดิม อย่างไรก็ตาม
คำตอบ #2
จาก TypeScript 2.1 วิธีที่ดีกว่าคือการใช้ keyof และ Mapped Types.
function test()
{
const my = new MyClass();
my.assign({ prop1: 3});
}
type MyClassPartial = {
[P in keyof MyClass]?: MyClass[P];
};
class MyClass
{
prop1: number;
prop2: string;
assign(props: MyClassPartial)
{
for (const key of Object.keys(props))
{
this[key] = props[key];
}
}
}
