Metode dinamice ale claselor în Typescript
Problemă
Cum poate cineva să adauge verificarea tipului la o metodă a unei clase create dinamic?
Exemplu
Având o clasă Property foarte simplă.
class Property {
value: any;
name: string;
constructor(name: string, value: any) {
this.name = name;
this.value = value
}
}
și o clasă Entity
class Entity {
name: string;
properties: Property[];
constructor(name: string, properties: Property[]) {
this.name = name;
this.properties = properties;
this.properties.forEach((p: Property, index: number) => {
this[p.name] = (value: string): any => {
if (value) {
this.properties[index].value = value;
}
return this.properties[index].value;
}
}, this);
}
}
Parte importantă: this[p.name]=function ... (nu știm numele metodei în momentul „transpile”).
Primim următoarea eroare atunci când transpilăm în JavaScript:
var car = new domain.Entity(
'car',
[
new domain.Property('manufacturer', 'Ford'),
new domain.Property('model', 'Focus')
]
);
car.model() // error TS2339: Property 'model' does not exist on type 'Entity'.
Știu că aceasta este o utilizare neobișnuită a claselor, deoarece diferite instanțe ale Entity vor avea metode diferite definite. Există vreo modalitate de a scăpa de eroare, adică TypeScript să poată identifica interfața corectă pentru fiecare instanță, sau cel puțin să se suprime eroarea?
Note
Acesta este javascript valid și cineva l-ar putea folosi în următorul mod:
var car = new domain.Entity(
'car',
[
new domain.Property('manufacturer', 'Ford'),
new domain.Property('model', 'Focus')
]
);
car.model() // 'Focus'
car.model('Transit') // 'Transit'
Sunt conștient că acest lucru a fost întrebat într-o întrebare asemănătoare, dar acest caz este puțin diferit, deoarece numele metodei este de asemenea definit la rulare.
Răspuns #1
Adaugă acest tip (doar o dată necesar):
interface Prop<T> {
(): T;
(value: T): T;
}
atunci poți să scrii asta pentru fiecare formă pe care o creezi:
interface Car extends Entity {
model: Prop<string>;
manufacturer: Prop<string>;
}
let car = <Car>new Entity('car', [/*...*/]);
car.model(32); // Error
let x = car.model(); // x: string
Răspunsul #2
Dacă ai proprietăți dinamice la care vrei să accesezi, atunci folosește tipul any pentru a ocoli verificările de tip pentru variabilă. Poți să declari variabila cu tipul any de la început, sau să folosești operatorul de aserțiune a tipului (as) mai târziu. Așadar, iată câteva variante posibile:
var car: any = new domain.Entity(...);
car.model();
var car = new domain.Entity(...) as any;
car.model();
var car = new domain.Entity(...);
(car as any).model();
