当我忽略泛型类型定义时,为什么打字稿不会抱怨?

Mei*_*des 6 generics typescript typescript-generics

假设您有以下代码:

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>());
Run Code Online (Sandbox Code Playgroud)

游乐场链接

你肯定会注意到,这里应该有一个错误。Superclass<Generic1>只能与 结合Superclass<Generic1>,但决不能与 结合Superclass<Generic2>。Visual Studio 代码也显示:

在此处输入图片说明

但是编译后没有错误!为什么?我误解了泛型吗?

Dai*_*Dai 5

TypeScript 允许它通过,因为TinSuperclass<T> 不影响它的 shape,因此Superclass<A>Superclass<B>具有相同的形状,因此被 TypeScript 认为是“兼容的”。

请记住,TypeScript 有一个结构类型系统,其中的成员认为类型是等效的,即使它们的实际定义和原始定义是完全分开的(想想收敛进化)。至于为什么是令人惊讶:请记住,打字稿也不能有记名式系统,其中类型具有相同的成员,结构和布局,一直到跨平台的二进制表示,被认为是严格的区别,只要它们有不同的类型-名称(这是 Java、C# 和许多其他语言的类型系统的工作方式)。

所以 whileSuperclass<T>不使用T并且不影响它的形状,所以tsc认为是T多余的而忽略它:

所以这...

class Superclass<T> {
    combine(object: Superclass<T>): Superclass<T> { ... }
}
Run Code Online (Sandbox Code Playgroud)

...可证明等价于:

class Superclass {
    combine(object: Superclass): Superclass { ... }
}
Run Code Online (Sandbox Code Playgroud)

但是,一旦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() ) );
Run Code Online (Sandbox Code Playgroud)

错误:

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'.
Run Code Online (Sandbox Code Playgroud)

至于为什么会这样- 这是(我认为)在 TypeScript 文档中关于Type Compatibility的部分中解释的:

TypeScript 的结构类型系统的基本规则x是与yify至少具有相同的成员x

在这种情况下, whenSuperclass<T>是关闭的,因为其中一个Superclass<Generic1>Superclass<Generic2>两个类型具有完全相同的成员,并且 TypeScript 认为它们彼此兼容。