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

时间:2017-12-11 22:19:46

标签: class typescript extends implements

很抱歉这个奇怪的标题,我不知道如何用一句话描述我想要做的事情。

我必须定义一堆类,这些类都将从这一个类扩展,并实现另一个类。

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

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

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,但我确实希望确保传递的类已扩展Super并实施BonBon

1 个答案:

答案 0 :(得分:1)

我猜测班级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);

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