You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 18:58:10