【问题标题】:Typescript superclass identifying from a decorator从装饰器识别的打字稿超类
【发布时间】:2020-06-12 15:29:18
【问题描述】:

我有一个像下面这样的抽象类

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

还有两个扩展基础的类

export class Boo extends Foo {
}

export class Moo extends Foo {
}

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

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

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

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

装饰器中有没有办法区分来​​自每个超类的调用?

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

谢谢。

【问题讨论】:

    标签: typescript superclass typescript-decorator


    【解决方案1】:

    因为您正在装饰原型方法,所以在评估装饰器所在的 class 构造时应用装饰器,而不是稍后创建实例时。它仅应用于该类的原型成员(子类仅通过继承获得修饰成员)。

    假设你有:

    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。如果您在上面的类定义之后有此代码:

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

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

    【讨论】:

    • 是的,我的问题实际上仍然令人困惑。很抱歉(你对类装饰器的解释也已经给了我一个提示)我想将new Boo().f1()new Moo().f1() 区分开来。适用于函数的装饰器规则与适用于类的装饰器规则相同吗?
    • @MichaelMichailidis - 您可以通过查看通话中的this 来区分new Boo().f1()new Moo().f1()。如果您不想依赖this(由于Function.prototype.call/apply,它可以是任何东西),您必须在子类中覆盖f1(然后可能使用super.f1() 来调用超类版本其中)。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2020-01-02
      • 2016-12-05
      • 2017-04-02
      • 2019-03-25
      • 2020-05-31
      • 2018-06-21
      • 2019-07-29
      • 2016-05-08
      • 1970-01-01
      相关资源
      最近更新 更多