I want to create an abstraction with the help of Typescript decorators and reflect-metadata. But when I invoke the function I pass into the metadata, this
is undefined:
import "reflect-metadata";
const METHODS = "__methods__";
const Method = (obj: object) => {
return function MethodDecorator(
target: object,
methodName: string | symbol,
descriptor: PropertyDescriptor
) {
const metadata = Reflect.getMetadata(METHODS, obj);
Reflect.defineMetadata(
METHODS,
{ ...metadata, [methodName]: descriptor.value },
obj
);
};
};
const someObject: object = new Object();
class Main {
private num = 42;
constructor(other: Other) {
other.init(someObject);
}
@Method(someObject)
myMethod() {
console.log("hello");
console.log(this.num); // this is undefined (how can I fix it?)
}
}
class Other {
private methods: Record<string, Function> = {};
init(obj: object) {
this.methods = Reflect.getMetadata(METHODS, obj);
}
trigger(methodName: string) {
this.methods[methodName]();
}
}
const other = new Other();
new Main(other);
other.trigger("myMethod");
The output of the code snippet above is
hello
undefined
this
undefined and how can I fix it?You can try it yourself by cloning this sample repo and running
yarn install
yarn start
If you save the value of this
by passing it to other.init
, as below, and then bind that value to each method, it will work. Unfortunately it does not seem possible to pass this
directly to the decorator, though that would be much cleaner.
const someObject: object = new Object();
class Main {
private num = 42;
constructor(other: Other) {
other.init(someObject, this);
}
@Method(someObject)
myMethod() {
console.log("hello");
console.log(this.num); // 42
}
}
class Other {
private methods: Record<string, Function> = {};
init(obj: object, thisArg: object) {
this.methods = Reflect.getMetadata(METHODS, obj);
Object.keys(this.methods).forEach((method) => {
this.methods[method] = this.methods[method].bind(thisArg);
})
}
trigger(methodName: string) {
this.methods[methodName]();
}
}
const other = new Other();
new Main(other);
other.trigger("myMethod");