Adding properties to a class via decorators in TypeScript

眉间皱痕 提交于 2020-01-14 09:05:44

问题


On the TypeScript's Decorator reference page there is a code snipped that illustrates how to override the constructor with class decorator:

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"));

and in logs:

class_1 {
  property: 'property',
  hello: 'override',
  newProperty: 'new property' }

So far so good. BUT trying to access newProperty by dot notation fails with:

Property 'newProperty' does not exist on type 'Greeter'.ts(2339)

error and it's not listed in hints in VS Code. One can access it by bracket notation but TS warns that

Element implicitly has an 'any' type because type 'Greeter' has no index signature.ts(7017)

Am I missing something? How to implement adding new properties via Decorators in type-safe way? I'd like to have normal compiler support just like with regular class members.


回答1:


Decorators by design can't change the type of a class. This is stil in discussion and it appears until the decorator proposal is finalized the team will not change the behavior. You can use mixins for this task (read about mixins in ts)

Using mixins the code would look something like:

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);



回答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);

Seems we can use interface trick to solve the problem. Reference of the trick: https://stackoverflow.com/a/52373394/4831179



来源:https://stackoverflow.com/questions/54813329/adding-properties-to-a-class-via-decorators-in-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!