为什么泛型类可以扩展类型形状?

时间:2019-09-23 04:02:44

标签: typescript

我是Typescript的新手,只是一个关于扩展类型形状的泛型类的问题,下面是一些示例代码:

class DataCollection<T extends { name: string }> {
   ...
}

这是有效的代码,似乎一个类可以扩展Sharp类型,但是如果我们这样编码,那是不正确的:

type Person = {
   name: string
}

class DataCollection extends Person {   // invalid code
   ...
}

这是无效的,因此类无法扩展Sharp类型。

通过这种方式,我们只能将类型Person作为接口和代码:

type Person = {
   name: string
}

class DataCollection implements Person {   //valid code
   ...
}

这意味着,将通用类用作以下内容更明智:

class DataCollection<T implements { name: string }> {
   ...
}

那么为什么泛型类只能扩展类型形状而不能实现类型形状?

1 个答案:

答案 0 :(得分:1)

尽管共享相同的语法,但这里有几个概念都不同。

引用type Name = ...定义的标准方法是类型别名而不是类型形状

首先,类型仅在编译时存在。因此,根据定义,在运行时没有任何东西可以依赖它们。这意味着在已编译的js中将不会以任何方式存在类型别名Person人。

类具有双重性质,它们的名称既表示类型(类的实例类型)又表示运行时值(用于初始化对象的构造函数)。

您说class DataCollection extends Person的意思是,在运行时时,类DataCollection需要向其原型链中添加Person的原型。由于类型别名在编译过程中被删除,因此类DataCollection的原型链中没有添加任何内容,这使得该声明对于类型别名(或接口)毫无意义。

当您说class DataCollection implements Person时,是在要求编译器确保在编译时class DataCollection的所有成员都具有Person类型的适当类型。这是一个纯粹的编译时操作,因此在这里使用类型别名是可以的。

T中的class DataCollection<T>是通用类型参数。通用类型参数可用于使一个类可用于多种数据类型,同时保留有关基础类型的信息:

class DataCollection<T> {
    add(value: T) {}
}
var c = new DataCollection<number>();
c.add(1)
c.add("1") // error

Play

请注意,T从未在运行时表达式中使用,仅在类型注释中使用,我们决不能在表达式中使用T(例如new T()无效) 。 T只是在编译时检查类的某些方面(参数,成员,返回值)是否具有在实例化类时指定的特定类型(在这种情况下,number在{{1}中指定)。

有时我们需要更多有关new DataCollection<number>的信息。例如,我们可能想要一个T成员。这是onAdded进入的地方。它使我们可以将DataCollection<T extends TYPE>约束为另一种指定类型的子类型:

T

Play

语法type WithAdd = { onAdd(): void } class DataCollection<T extends WithAdd> { add(value: T) { value.onAdd(); // ok since onAdd is on the constraint of T value.onAdded(); // error since onAdded is not on the constraint of T } } class Person { name!: string; onAdd(): void { } } var cErr = new DataCollection<number>(); // error number does not have onAdd var c = new DataCollection<Person>() c.add(new Person()) c.add({ onAdd() { } }) // error not a Person 在打字稿中没有任何意义。由于约束中的DataCollection<T implements { name: string }>已经只处理类型,因此说extends扩展类型或T实现类型之间的含义确实没有区别。在这两种情况下,T都是指定类型的子类型,因此在没有添加任何值的情况下,两者都将造成混乱。至于为什么选择T而不是extends,这是所有人的猜测。