Search code examples
typescriptaop

Can I add a property to a class at compile time via a decorator?


I have the following code

export class TestClass {
    query<TId, TRequest extends TId, TResponse extends TId>(request: TRequest) : TResponse {
        return null;
    }

    test() {
        let request = new SomeQuery1();
        let response = this.query<{ "a b c" }, SomeQuery1, SomeResponse1>(request);
    }
}

class SomeQuery1 {
    public "a b c": string;
}
class SomeResponse1 {
    public "a b c": string;
}

The "a b c" bit is just a marker I am playing with that lets the generic constraint know that these two classes are in some way related. I intend to use a unique name. But anyway, what I would like to do is this

@myDecorator("a b c")
class SomeQuery1 {
}
@myDecorator("a b c")
class SomeResponse1 {
}

//Is effectively the same as this
class SomeQuery1 {
    public "a b c": string;
}
class SomeResponse1 {
    public "a b c": string;
}

So that the original TestClass will still employ the same strongly typed checking at compile time. Is this possible with a decorator, or any other TypeScript mechanism?


Solution

  • Decorators are not designed to mutate the class prototype.

    There is a request in the official TypeScript repository to support the mutation of classes via decorators.

    For the time being, you can use a decorator to add metadata using reflect-metadata. Then you can validate at runtime that the class has that metadata and throw an exception if it is required but missing.