TypeScript如何通过装饰器识别方法调用来源的子类
如何在装饰器中区分基类方法的调用子类
首先得戳破一个关键误区:装饰器是在类定义的阶段执行的,而不是在方法被调用的时候执行的!
你之前尝试检查target的原型和构造函数,但这个target其实是基类Foo的原型——因为当装饰器运行时,子类Boo和Moo要么还没被定义,要么还没完成实例化,装饰器根本接触不到子类的实例或原型。这就是你无法识别调用来源的核心原因。
那要实现“区分调用该方法的子类”,得换个思路:让装饰器包装原方法,在方法被实际调用时,通过this来判断当前实例所属的子类。因为方法调用时,this会指向具体的子类实例,我们可以通过它来识别来源。
具体实现代码
修改你的装饰器Bla,让它返回一个包装后的方法:
export function Bla() { return (target: any, key: string, descriptor: PropertyDescriptor) => { // 保存原方法的引用 const originalMethod = descriptor.value; // 替换成包装后的方法逻辑 descriptor.value = function(...args: any[]) { // 在这里通过this判断当前实例的子类归属 if (this instanceof Boo) { console.log("调用来源是Boo子类"); } else if (this instanceof Moo) { console.log("调用来源是Moo子类"); } // 也可以直接获取构造函数名称做标识 console.log(`当前实例所属类:${this.constructor.name}`); // 执行原方法并返回结果 return originalMethod.apply(this, args); }; return descriptor; }; }
你的基类和子类代码保持不变:
export abstract class Foo { @Bla() public f1() { console.log("执行f1核心逻辑"); } } export class Boo extends Foo { } export class Moo extends Foo { }
测试调用效果:
const boo = new Boo(); boo.f1(); // 输出: // 调用来源是Boo子类 // 当前实例所属类:Boo // 执行f1核心逻辑 const moo = new Moo(); moo.f1(); // 输出: // 调用来源是Moo子类 // 当前实例所属类:Moo // 执行f1核心逻辑
注意事项
- 包装方法必须用普通函数,不能用箭头函数:箭头函数的
this会绑定到装饰器执行时的上下文(即基类Foo的原型),无法拿到调用时的子类实例。 - 如果存在多层继承(比如
class Goo extends Boo),instanceof会正确识别层级关系,你可以根据需求调整判断逻辑。 - 由于
Foo是抽象类,无法直接实例化,所以不用考虑this instanceof Foo的常规场景。
内容的提问来源于stack exchange,提问作者Michael Michailidis
相关产品推荐
相关产品推荐

