如何在打字稿中为通用参数添加 "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 {}
引入了一个名为 Zoo
的 type,这是 class 的实例类型,以及一个 value 命名为Zoo
,这是此类实例的构造函数。而且 Zoo
值的类型不是 Zoo
类型。要引用 Zoo
构造函数值的类型,您需要使用 typeof Foo
代替:
class Zar implements Bar<typeof Zoo> { } // okay
此外,我假设您已经删除了 Bar
、Zar
和 Zoo
的内容,因为它们与此处无关。但要明确一点,空接口几乎可以匹配所有内容,因为 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
}
希望对您有所帮助。祝你好运!
我已经知道如何为函数参数添加 "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 {}
引入了一个名为 Zoo
的 type,这是 class 的实例类型,以及一个 value 命名为Zoo
,这是此类实例的构造函数。而且 Zoo
值的类型不是 Zoo
类型。要引用 Zoo
构造函数值的类型,您需要使用 typeof Foo
代替:
class Zar implements Bar<typeof Zoo> { } // okay
此外,我假设您已经删除了 Bar
、Zar
和 Zoo
的内容,因为它们与此处无关。但要明确一点,空接口几乎可以匹配所有内容,因为 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
}
希望对您有所帮助。祝你好运!