jantimon
jantimon

Reputation: 38140

Is it possible to type properties added by a decorator?

Let's say I have a decorator like in the following example which adds a new name property with a preset value.

Is there any way to tell typescript that my decorator adds this property so that all decorated classes are typed correctly?

Example code:

function withName(name) {
    return (target) => {
        target.prototype.name = name;
    }
}

@withName('Karl')
class Person {
    greet() {
        console.log("Hi I'm ", this.name);
  }    
}


const karl = new Person();
karl.greet(); // Will log: "Hi I'm Karl"

console.log(karl.name); // <- Will cause a TypeScript error: "Property 'name' does not exist on type 'Person'"

Upvotes: 3

Views: 174

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249646

Decorators by design are not allowed to change the structure of the type they are decorating. A supported way of doing this would be to use a mixin, as described here

function withName(nameValue: string) {
    return <T extends new (...args: any[]) => any>(target: T) => {
        return class extends target {
            name: string = nameValue
        }
    }
}
const Person = withName("Karl")(class {
    greet() {
        console.log("Hi I'm ...");
    }
});
const karl = new Person();
console.log(karl.name);

The approach above only augments the class to the outside world so the added members are not visible from inside the class. We could augment the base class of Person (or use an empty class if there is no base class) to get access to the added fields inside the augmented class:

class Person extends withName("Karl")(class { }) {
    greet() {
        console.log("Hi I'm ", this.name);
    }
}

const karl = new Person();
karl.greet(); // Will log: "Hi I'm Karl"

Upvotes: 3

Related Questions