Reputation: 1052
I have an abstract class like the following
export abstract class Foo {
public f1() {
}
}
and two more classes extending the base
export class Boo extends Foo {
}
export class Moo extends Foo {
}
Now I have a custom decorator like the following
export function Bla() {
return (target: any, key: string, descriptor: PropertyDescriptor) => {
}
}
so my initial class is the following (with the decorator)
export abstract class Foo {
@Bla
public f1() {
}
}
is there a way in the decorator to distinguish which call sourced from each superclass?
so far what I have tried are checking prototypes / constructors of target
but I do not seem to find a way to access / understand from which class it was sourced. Is there a way to figure it out or I am doing something really wrong?
Thank you.
Upvotes: 1
Views: 705
Reputation: 31924
The trick to it is tapping into the method call itself and inspecting the class instance:
function Bla(target: any, propKey: string | symbol | d: PropertyDescriptor) {
let originalMethod = target[propKey];
// return new property descriptor for the method, replacing the original one
return {
value: function () {
let instance = this; // will be the instance ref because of 'function' literal
let classReference = instance.constructor; // <-- this is what we need
if (classReference === Boo) {
// called from Boo class
}
// call original method
return originalMethod.apply(this, arguments);
}
}
}
Upvotes: 2
Reputation: 1074335
Because you're decorating a prototype method, the decorator is applied when class
construct the decorator is in is evaluated, not later when instances are created. It's only applied to the prototype member for that class (subclasses only get the decorated member via inheritance).
Assuming you have:
function Bla() {
return (target: any, key: string, descriptor: PropertyDescriptor) => {
console.log(target.constructor.name);
}
}
abstract class Foo {
@Bla()
public f1() {
}
}
// At this point, you see "Foo" in the console
class Boo extends Foo {
}
class Moo extends Foo {
}
The decorator will run when class Foo
is evaluated, not later when you create instances. You can see this happen in the playground. If you have this code after the class definitions above:
setTimeout(() => {
new Boo; // Nothing shows in the console
setTimeout(() => {
new Moo; // Nothing shows in the console
console.log("Done");
}, 1000);
}, 1000);
If you were decorating an instance member, you'd be able to differentiate because the instance would be a Boo
or Moo
, but not when you're decorating a prototype member.
Upvotes: 1