从装饰器识别的 Typescript 超类

Typescript superclass identifying from a decorator

我有一个摘要class如下

export abstract class Foo {
  public f1() {
  }
}

和另外两个 classes 扩展基础

export class Boo extends Foo {
}

export class Moo extends Foo {
}

现在我有一个像下面这样的自定义装饰器

export function Bla() {
  return (target: any, key: string, descriptor: PropertyDescriptor) => {
  }
}

所以我的初始 class 如下(带有装饰器)

export abstract class Foo {
 @Bla
 public f1() {
 }
}

装饰器中有没有办法区分哪个调用来自每个超级class?

到目前为止,我所尝试的是检查 target 的原型/构造函数,但我似乎没有找到一种方法来访问/理解它的来源 class。有没有办法弄清楚,或者我做错了什么?

谢谢。

因为您正在装饰原型方法,所以当 class 对装饰器所在的构造进行求值时应用装饰器,而不是稍后创建实例时应用装饰器。它仅适用于 class 的原型成员(subclasses 仅通过继承获得装饰成员)。

假设您有:

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 {
}

装饰器将在 class Foo 计算时 运行,而不是稍后创建实例时。你可以看到这种情况发生 in the playground。如果您在上面的 class 定义之后有此代码:

setTimeout(() => {
    new Boo; // Nothing shows in the console
    setTimeout(() => {
        new Moo; // Nothing shows in the console
        console.log("Done");
    }, 1000);
}, 1000);

如果您正在装饰一个实例成员,您将能够区分,因为该实例将是 BooMoo,但在您装饰原型成员时则不然。

它的诀窍是利用方法调用本身并检查 class 实例:

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);
    }
  }
}