Adăugarea de proprietăți unei clase prin decoratori în TypeScript
Pe pagina de referință a Decoratorului din TypeScript există un fragment de cod care ilustrează cum să suprascrii constructorul cu un decorator de clasă:
function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
return class extends constructor {
newProperty = "new property";
hello = "override";
}
}
@classDecorator
class Greeter {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
}
console.log(new Greeter("world"));
și în jurnale:
class_1 {
property: 'property',
hello: 'override',
newProperty: 'new property' }
Până acum totul bine. DAR încercarea de a accesa newProperty prin notație punctată eșuează cu:
Proprietatea 'newProperty' nu există pe tipul 'Greeter'.ts(2339)
eroare și nu este listată în sugestii în VS Code. Se poate accesa prin notația cu paranteze, dar TS avertizează că
Elementul are implicit tipul 'any' deoarece tipul 'Greeter' nu are semnătură de index.ts(7017)
Îmi scapă ceva? Cum să implementez adăugarea de proprietăți noi prin Decoratori într-un mod sigur pentru tipuri? Aș dori să am suport normal al compilatorului, exact ca și cu membri normali ai clasei.
Răspuns #1
Decoratorii prin design nu pot schimba tipul unei clase. Acest lucru este încă în discuție și se pare că până când propunerea pentru decorator nu este finalizată, echipa nu va schimba comportamentul. Poți folosi mixin-uri pentru această sarcină (citește despre mixin-uri în ts)
Folosind mixin-uri, codul ar arăta cam așa:
function classDecorator<T extends { new(...args: any[]): {} }>(constructor: T) {
return class extends constructor {
newProperty = "new property";
hello = "override";
}
}
const Greeter = classDecorator(class {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
});
type Greeter = InstanceType<typeof Greeter> // have the instance type just as if we were to declare a class
console.log(new Greeter("world").newProperty);
Răspunsul #2
function classDecorator<T extends { new(...args: any[]): {} }>(constructor: T) {
return class extends constructor {
newProperty = "new property";
hello = "override";
}
}
interface classInterface {
newProperty: string;
hello: string;
}
//trick
interface Greeter extends classInterface { };
@classDecorator
class Greeter {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
}
const b = new Greeter();
console.log(b.newProperty);
Se pare că putem folosi trucul cu interfața pentru a rezolva problema. Referința trucului: https://stackoverflow.com/a/52373394/4831179
