There are many subtleties to your question.
The first thing is, yes, you can indeed use a method as a decorator, but not by writing @this.decorate (during transpiling, this would be the globalThis instead of A) or @A.decorate (decorate is not a static method, so A.decorate does not exist). The correct answer to this part of the question is @A.prototype.decorate; this will locate exactly what you have in mind.
The second thing is, when applying a decorator to a method of a class, the argument of the decorator is not the method function itself, but it actually have 3 arguments: a target object (which would be A.prototype in our case), a string (the name of the method, which is "method" in our case), and a property descriptor object. It also does not return a new function, but it should return a new property descriptor if not void. So inside the decorator function, you should try to modify the target object instead of trying to return a new function.
Putting things together, a working example will be:
class A {
private mySecretNumber = 2;
decorate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
var f = descriptor.value;
// Don't use arrow function here, otherwise "this"
// will not be the current A instance.
descriptor.value = function(x: number) {
return f(this.mySecretNumber * x);
};
Object.defineProperty(target, propertyKey, descriptor);
}
@A.prototype.decorate
method(x: number) {
return x + 1;
}
}
var a = new A();
console.log(a.method(3)); // 7
Update:
Based on your use case, I will use the following approach. Basically you use a static decorator to load the abstract decorate method, which can be implemented in subclasses. I modify the example above to give you an idea how it can be done.
abstract class A {
protected abstract decorate(x: number): number;
static decorate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
var f = descriptor.value;
descriptor.value = function(x: number) {
return f(this.decorate(x));
};
Object.defineProperty(target, propertyKey, descriptor);
}
@A.decorate
method(x: number) {
return x + 1;
}
}
class B extends A {
private mySecretNumber = 2;
protected decorate(x: number) { return this.mySecretNumber * x; }
}
var b = new B();
console.log(b.method(3)); // 7