如何在打字稿中为通用参数添加 "newable" 约束?

How to add "newable" constraint for generic parameter in typescript?

我已经知道如何为函数参数添加 "newable"(即具有构造函数)约束(如下面 foo 函数的参数),但相同的技术不适用于泛型类型参数。

这是为什么以及如何解决?

type NoParameterCtor<T> = { new(): T }

function foo<T>(ctor: NoParameterCtor<T>) { }

interface Bar<T extends NoParameterCtor<T>> { }

class Zoo { }

foo(Zoo) 
// no compiler error

class Zar implements Bar<Zoo> { }
// Type 'Zoo' does not satisfy the constraint 'NoParameterCtor<Zoo>'

如评论中所述,T extends NoParameterCtor<T> 是一个不寻常的约束,这意味着“T 是一个创建自身新实例的构造函数”。除非你试图描述自我复制的构造函数,否则这不是你的意思。

如果你只想T做"anything newable",那么你不需要关心实例类型。假设您使用的是 TS3.0 或更高版本,您可以使用 unknown 来表示任何类型,尽管您也可以使用 any。所以也许你希望 Bar 成为

interface Bar<T extends NoParameterCtor<unknown>> { }

以下仍然无效:

class Zar implements Bar<Zoo> { } // error! 
// Zoo does not satisfy the constraint NoParameterCtor<unknown>

那是因为类型 Zoo 不可更新;它是 Zoo class 的实例类型。我不知道您是否对 TypeScript 中的 感到困惑,但如果是这样的话,您的公司很好。简而言之,class Zoo {} 引入了一个名为 Zootype,这是 class 的实例类型,以及一个 value 命名为Zoo,这是此类实例的构造函数。而且 Zoo 值的类型不是 Zoo 类型。要引用 Zoo 构造函数值的类型,您需要使用 typeof Foo 代替:

class Zar implements Bar<typeof Zoo> { } // okay

此外,我假设您已经删除了 BarZarZoo 的内容,因为它们与此处无关。但要明确一点,空接口几乎可以匹配所有内容,因为 TypeScript 使用 structural typing. If Bar needs access to the instance type of T, then you can use the built-in library type alias InstanceType<> 来获取它:

interface Bar<T extends NoParameterCtor<unknown>> {
   theConstructor: T,
   theInstance: InstanceType<T>
}

class Zar implements Bar<typeof Zoo> { 
  theConstructor = Zoo; // the constructor
  theInstance = new Zoo(); // an instance
}

希望对您有所帮助。祝你好运!