Class 装饰器,如何确保 class 正在扩展和实现其他 classes

Class decorator, how to make sure the class is extending and implementing other classes

抱歉这个奇怪的标题,我不太清楚如何用一句话描述我想做的事情。

我必须定义一堆 classes,它们都将从这个 class 扩展并实现另一个 class.

class SoulCoughing extends Super implements BonBon { /.../ }
class MoveAside extends Super implements BonBon { /.../ }
class LetTheManGoThru extends Super implements BonBon { /.../ }

我编写了一种包装函数,用作这些 classes 的装饰器。

const Eminem = function(klass: Constructable<????>) {
  const instance = new klass();
  // Do stuff
}

Constructable 是我正在使用的一个小接口,否则 TypeScript 会抛出一个关于没有构造函数的错误。

interface Constructable<T> {
  new(): T;
}

现在这是我的问题,我不知道在包装函数中为参数 klass 分配什么类型?我试过这样做:

... function(klass: Contrusctable<Super & BonBon>)

还有这个:

... function(klass: Contrusctable<Super | BonBon>)

我也试过像这样修改我的可构造界面:

interface Constructable<T, U> {
  new(): T & U;
}

... function(klass: Contrusctable<Super, BonBon>)

但我一直收到 Argument of type 'typeof SoulCoughing' is not assignable to parameter of type 'Constructable<everythingIveTriedSoFar>' 错误。

所以我的问题是,我应该对参数 klass 使用什么类型定义?我知道我可以只使用 any,但我真的很想确保传递的 class 已经扩展 Super 并实现了 BonBon

我猜测 类 SoulCoughing 等实际上没有无参数构造函数,因此根本不能充当 Constructable<{}>;最有可能的罪魁祸首是 Super 的构造函数有一个强制参数,这将使所有子 类 默认情况下无法匹配 new()。请注意,这也意味着您对 Eminem 的实现可能还想用一些参数调用 new klass(...)

修复它的正确方法是将 Constructable<T> 声明为具有正确参数类型的构造函数。假设 Super 看起来像这样:

class Super {
  constructor(elevator: number, mezzanine: string) {
    //...
  }
}

然后你可以定义Constructable来匹配:

interface Constructable<T extends Super & BonBon = Super & BonBon> {
  new(chump: number, change: string): T; // same args as Super
}

Eminem喜欢:

const Eminem = function(klass: Constructable) {
  const instance = new klass(2, "rise");
  // Do stuff
}

最后:

Eminem(SoulCoughing); // no error

我只保留 Constructable 泛型,以防您希望 TypeScript 保留特定子类的类型,如下所示:

const SlimShady = function <T extends Super & BonBon>(klass: Constructable<T>): T {
  return new klass(2, "fat");
}

// returns same type as passed-in constructor
const cutLean: MoveAside = SlimShady(MoveAside);

好的,希望对你有帮助;祝你好运!