【问题标题】:Writing a TypeScript decorator to always bind class methods to 'this'编写 TypeScript 装饰器以始终将类方法绑定到“this”
【发布时间】:2018-04-19 00:02:50
【问题描述】:

我正在尝试编写一个装饰器来始终将类方法的范围绑定到该类的实例。

这是我目前的实现:

function LockThis<T extends { new(...args: any[]): {} }>(constructor: T) {
  let self: any;
  const locker = class extends constructor {
    constructor(...args: any[]) {
      super(...args);
      self = this;
    }
  };
  const proto = constructor.prototype;
  Object.getOwnPropertyNames(proto).forEach(key => {
    if (key === 'constructor') {
      return;
    }
    const descriptor = Object.getOwnPropertyDescriptor(proto, key);
    if (descriptor && typeof descriptor.value === 'function') {
      const original = descriptor.value;
      locker.prototype[key] = (...a: any[]) => original.apply(self, a);
    }
  });
  return locker;
}

@LockThis
class Something {
  private foo = 'bar';

  public doIt(someVar?: string) {
    return this.foo + ' ' + someVar;
  }
}

const something = new Something();
console.log(something.doIt.call({}, 'test'));
--> bar test

这有效,抽象类除外:

@LockThis
abstract class Blah {

}

TS2345: Argument of type 'typeof Blah' is not assignable to parameter of type 'new (...args: any[]) => {}'.
  Cannot assign an abstract constructor type to a non-abstract constructor type.

是否有不同的类型保护可用于允许实际类和抽象类和/或替代方法来执行此操作?

(我对每个方法的尝试都是徒劳的,因为在调用方法之前我似乎无法确定“this”,如果使用不同的范围调用就太晚了)

class Something {
  private foo = 'bar';

  @LockThis()
  public doIt(someVar?: string) {
    return this.stuff + ' ' + someVar;
  }
}

【问题讨论】:

    标签: class typescript scope decorator abstract


    【解决方案1】:

    根据Microsoft/TypeScript#5843,没有很好的方法来引用抽象构造函数类型。其中提到的解决方法是只使用Function,这太宽松了(并非所有函数都是构造函数),但可能对您有用,因为您不太可能尝试在随机函数上使用类装饰器。

    你不能在Function 上做一个mixin,所以实现需要仍然认为你有一个构造函数。因此,我建议您在LockThis 上使用function overload,以便调用者看到Function,但实现仍然看到它可以扩展的构造函数。例如:

    // callers see a function that takes any function and returns the same type
    function LockThis<T extends Function>(constructor: T): T;
    
    // implementation is unchanged, and still sees a (concrete) constructor
    function LockThis<T extends { new(...args: any[]): {} }>(constructor: T) {
      // ... your unchanged implementation here
    }
    

    现在可以了:

    @LockThis // no error
    abstract class Blah { } 
    

    这是我能得到的最接近你想要的东西。希望有帮助;祝你好运!

    【讨论】:

      猜你喜欢
      • 2019-05-19
      • 2017-04-11
      • 2019-11-12
      • 2020-08-23
      • 1970-01-01
      • 2011-10-05
      • 2021-01-28
      • 2015-02-06
      • 2021-06-17
      相关资源
      最近更新 更多