为什么用InstanceType
错了在泛型上?是协变的还是逆变的?
interface Ctor {
new(): Instance;
}
interface Instance {
print(): void;
}
function f1<T extends Ctor>(ctor: T) {
// Error: Type 'Instance' is not assignable to Type 'InstanceType<T>'
const ins: InstanceType<T> = new ctor();
ins.print();
}
function f2(ctor: Ctor) {
// No error
const ins: InstanceType<Ctor> = new ctor();
ins.print();
}
Playground Link
最佳答案
这是我认为的问题:Typescript 确定表达式的编译时类型 new ctor()
通过查看 ctor
的类型(即 T
),检查 T
必须有一个构造函数签名(它有),然后找到 T
的构造函数签名是什么返回。但是T
可以是 Ctor
的任何子类型,所以它的构造函数签名可以返回 Instance
的任何子类型.
在这种情况下,编译器可以做两件合理的事情:
R extends Instance
),然后让表达式的类型 new ctor()
是 R
, Instance
. Typescript 做后者,也许是因为 Typescript 只有在你告诉它的情况下才会创建类型变量;它从不隐含地这样做。这使表达式的类型比赋值给
InstanceType<T>
所需的类型更弱。进行类型检查,因为 InstanceType<T>
确实显式地创建了一个类型变量 R
(在条件类型中使用 infer
子句),它可以是 Instance
的任意子类型.所以表达式的类型
new ctor()
是 Instance
,但赋值目标的类型注释(不是真的,但在某种意义上)是一个类型变量 R
可以是 Instance
的任何子类型,因此存在类型错误。一个可能的解决方案是为返回类型显式创建一个类型变量,如下所示:
function f1<R extends Instance, T extends {new(): R}>(ctor: T) {
const ins: R = new ctor();
ins.print();
}
也就是说,只有当您的函数处理 R
时才值得这样做。以其他一些能力,例如具有涉及 R
的返回类型.否则,您的代码使用 ins
必须适用于 R
的任何实现包括 Instance
本身,因此您不妨将其类型声明为 Instance
反正。 (同样,如果您的函数不在其他任何地方使用 T
,您不妨改为使用参数类型 Ctor
)。
关于typescript - 为什么在泛型上使用 InstanceType 是错误的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66405673/