假设您有以下代码:
class Superclass<T>{
combine(object: Superclass<T>) {
console.log("combined!");
return object;
}
}
class Generic1 {
x = 12;
// some class...
}
class Generic2 {
y = "Hello!";
// some class...
}
new Superclass<Generic1>().combine(new Superclass<Generic2>());
你肯定会注意到,这里应该有一个错误。 Superclass<Generic1>
只能与 Superclass<Generic1>
组合,但不能与 Superclass<Generic2>
组合。 Visual Studio 代码也显示:
但是编译后没有错误!为什么?我误解了泛型吗?
答案 0 :(得分:5)
TypeScript 允许它通过,因为 T
中的 Superclass<T>
不影响其形状,因此 Superclass<A>
和 Superclass<B>
具有相同的形状,因此被 TypeScript 认为是“兼容的”。
请记住,TypeScript 有一个结构 类型系统,其中的成员认为类型是等效的,即使它们的实际定义和原始定义是完全分开的(想想 convergent evolution)。至于为什么令人惊讶:请记住,TypeScript 确实没有有一个主格类型系统,其中具有相同成员、结构和布局的类型,一直到跨平台的二进制表示,都被认为是完全不同的,如只要它们具有不同的类型名称(这就是 Java、C# 和许多其他语言的类型系统的工作方式)。
所以虽然 Superclass<T>
没有使用 T
并且它不影响它的形状,所以 tsc
认为 T
是多余的并忽略它:
所以这个...
class Superclass<T> {
combine(object: Superclass<T>): Superclass<T> { ... }
}
...可证明等价于:
class Superclass {
combine(object: Superclass): Superclass { ... }
}
然而,一旦 Superclass<T>
依赖于 T
,例如添加一个类型为 T
的字段,它就会抛出一个错误:
class Superclass<T>{
public value: T;
constructor(value: T) {
this.value = value;
}
combine(object: Superclass<T>) {
console.log("combined: " + object.value.toString());
return object;
}
}
class Generic1 {
x = Math.random();
}
class Generic2 {
y = Math.random();
}
var x = new Superclass<Generic1>( new Generic1() ).combine(new Superclass<Generic2>( new Generic2() ) );
错误:
Argument of type 'Superclass<Generic2>' is not assignable to parameter of type 'Superclass<Generic1>'.
Property 'x' is missing in type 'Generic2' but required in type 'Generic1'.
至于 为什么会这样 - 这是(我认为)在 TypeScript 的文档中解释的in the section about Type Compatibility:
<块引用>TypeScript 的结构类型系统的基本规则是 x
与 y
兼容,如果 y
至少具有与 x
相同的成员
在这种情况下,当 Superclass<T>
关闭为 Superclass<Generic1>
或 Superclass<Generic2>
时,两种类型都具有完全相同的成员,并且 TypeScript 认为它们彼此兼容。