I've been playing with TypeScript decorators but just having no luck getting them working. I read How to implement a typescript decorator? and also http://blog.wolksoftware.com/decorators-reflection-javascript-typescript from which I created the decorator implementation
function log(target: any, key: string, descriptor?: any) {
// save a reference to the original method
// this way we keep the values currently in the
// descriptor and don't overwrite what another
// decorator might have done to the descriptor.
if(descriptor === undefined) {
descriptor = Object.getOwnPropertyDescriptor(target, key);
}
var originalMethod = descriptor.value;
//editing the descriptor/value parameter
descriptor.value = function (...args: any[]) {
var a = args.map(a => JSON.stringify(a)).join();
// note usage of originalMethod here
var result = 12;//originalMethod.apply(this, args);
var r = JSON.stringify(result);
console.log(`Call: ${key}(${a}) => ${r}`);
return result;
}
// return edited descriptor as opposed to overwriting
// the descriptor by returning a new descriptor
return descriptor;
}
class C {
constructor(){
console.log("built");
}
@log
public foo(n: number) {
console.log("foo called");
return n * 2;
}
}
//new MethodDecoratorExample().method("hi");
var c = new C();
var r = c.foo(23); // "Call: foo(23) => 12"
console.log(r);
However running this code doesn't yield what I expect, in fact it doesn't seem to override the descriptor. Digging in more I find that in the generated code the call to __decorate
has only three parameters
__decorate([
log
], C.prototype, "foo");
This means that in __decorate c = 3 as the descriptor is not passed in. As a result the new descriptor isn't returned and the code flow progresses as if the method hasn't been intercepted.
So I must be applying this decorator incorrectly but I can't see how I'm doing it wrong. Is it perhaps being interpreted as a property descriptor? I did see some comment about that somewhere but that was in relation to defining the foo method in C as a lambda which I'm not doing.
How can I get this working?
The issue here is that TypeScript will generate ES3 code by default, and method decorators generated for ES3 apparently work somewhat differently than the ones generated for ES5. So, unless you actually need to target ES3 the simple way to fix your problem is to target ES5 with tsc --experimentalDecorators --target es5
, or ES6 with tsc --experimentalDecorators --target es6
.