为什么我能这么做?

interface Base {
  [key: string]: any;
}

class Class {
  constructor(arg: Base) {    
    arg.newProp = 8;
  }
}

但不能这么做?

interface Base {
  [key: string]: any;
}

class Class<T extends Base> {
  constructor(arg: T) {    
    arg.newProp = 8;
  }
}

推荐答案

特定类型X与Ageneric类型参数TconstrainedX不同,如T extends X.您对T所做的任何操作都需要适用于可赋值给Xevery possible type.例如,如果X{a: string},则您对T extends X所做的任何操作都需要适用于X的子类型,如{a: string, b: number}{a: "x" | "y"}.如果你有一个X类型的变量x,你可以写x.a = "hello",但如果你有一个T extends X类型的变量t,你cannott.a = "hello",因为如果T变成{a: "x" | "y"},这就不起作用了.


在您的示例中,特定类型XBase,定义为{[k: string]: any},字符串index signature的属性是the any type.这是一种非常松散的类型:它本质上意味着可以具有任何键和任何值的属性的类型.所以如果argBase类型,那么你可以赋值arg.newProp = 8.

T extends Base是不同的;您所做的任何事情都需要对Base的每个可能的子类型有效.由于Base是如此松散,所以Base有许多相互不兼容的子类型可供 Select .例如,{a: string}Base的子类型:

const v = { a: "hello" };
new Class(v); // okay
v.newProp = 8; // error, Property 'newProp' does not exist

而且该类型不知道有一个newProp键,所以当您试图将8赋给它的newProp属性时,编译器会报错.这样的分配可能是无害的,但TS不会让你分配给它不确定是否存在的键.103 can lack an index signature when 104 has one有点奇怪,但这就是为什么您会收到错误消息的原因.


此外,{newProp: string}Base的一个子类型:

const n = { newProp: "str" };
new Class(n);
n.newProp = 8; // error, number not assignable to string

对于您的实现来说,这无疑是一个更糟糕的问题.如果您传入的值已经有一个newProp属性,并且8不可赋值给它,那么您的类实现将做一些不受欢迎的事情.


注意:这些问题也可能在特定类型中出现:new Class(v)new Class(n)行仍然使用Class的非泛型版本进行编译,导致与上面相同的令人不快的后果.Typescript 的排字系统是intentionally unsound in places.因此,您使用泛型所做的操作并不是"错误的",而另一个版本则是"正确的".

只是类型脚本假定您使用的是泛型,因为您需要这种额外的全能子类型判断.相反,如果您不想进行这种判断,则应该使用特定类型而不是泛型类型.或者,如果您确实使用泛型,那么您将需要使用type assertions或类似的方法来根据您的喜好放松类型判断.

Playground link to code

Typescript相关问答推荐

如何从具有给定键列表的对象类型的联合中构造类型

角形标题大小写所有单词除外

如何根据模板类型实现不同的模板函数行为?

有没有办法解决相互影响的路由之间的合并?

具有继承的基于类的react 组件:呈现不能分配给基类型中的相同属性

如果数组使用Reaction-Hook-Form更改,则重新呈现表单

防止重复使用 Select 器重新渲染

基元类型按引用传递的解决方法

为什么我在这个重载函数中需要`as any`?

无法将从服务器接收的JSON对象转换为所需的类型,因此可以分析数据

在打字脚本中对可迭代对象进行可变压缩

如何在try 运行独立的文字脚本Angular 项目时修复Visual Studio中的MODULE_NOT_FOUND

使用来自API调用的JSON数据的Angular

如何键入对象转换器

如何使函数参数数组不相交?

类型判断数组或对象的isEmpty

我可以将一个类型数组映射到TypeScrip中的另一个类型数组吗?

如何避免TS2322;类型any不可分配给类型never;使用索引访问时

覆盖高阶组件中的 prop 时的泛型推理

基于泛型的柯里化函数的条件参数