Typescript 索引属性约束检查适用于原始类型但不适用于对象文字?

Posted

技术标签:

【中文标题】Typescript 索引属性约束检查适用于原始类型但不适用于对象文字?【英文标题】:Typescript indexed properties constraint checks working on raw types but not on object literals? 【发布时间】:2017-07-07 02:29:36 【问题描述】:

有这个接口声明:

interface Thing1 
    [key: string]: string;
    x: number;

Typescript 在编译时抛出错误“TS2411:类型编号的属性 'x' 不可分配给字符串索引类型 'string'”

听起来很合法。

但是,只要我使用对象字面量作为索引类型值:

interface Foo 
interface Thing2 
    [key: string]: Foo;
    foo: number;

...它不再抱怨了,这对我来说听起来很奇怪,因为 number 仍然是与 Foo 不同的类型

你知道这背后的原因吗?

注意:使用 Typescript 2.1.5

【问题讨论】:

【参考方案1】:

空接口与简单类型(数字、字符串)兼容。如果你这样写,Typescript 不会抱怨:

let c: Foo = 3;

因此,在 Thing2 中,打字稿推断仍将 Foo 视为与数字兼容。但是,当索引签名是像 Thing1 中那样的字符串时,所有成员都应该是字符串(如您所述)。

【讨论】:

【参考方案2】:

这是由于 type compatibility 在 TypeScript 中的工作方式:

TypeScript 中的类型兼容性基于结构子类型。结构类型是一种仅基于其成员关联类型的方法。这与名义类型不同。

所以,这行得通:

interface Foo 
let f: Foo = 3;

因为 上的每个属性,Number 上都有一个名称和类型相同的属性。

这意味着这不起作用:

interface Foo 
let f: Foo = 3;
let b: number = f;

编译器抱怨let b: number = f;

类型 'Foo' 不能分配给类型 'number';

再次,来自文档:

TypeScript 的结构化类型系统是根据 javascript 代码的典型编写方式设计的。由于 JavaScript 广泛使用函数表达式和对象字面量等匿名对象,因此使用结构化类型系统而不是名义上的类型系统来表示 JavaScript 库中发现的各种关系要自然得多。

【讨论】:

我知道结构类型,但是,我从没想过一个数字会具有与对象字面量完全相同的“结构”(就其 API 而言)。诡异的。 :-) @Frédéric 需要明确的是,数字没有相同的结构,只是 上的每个属性在Number 上都有一个具有相同名称和类型的属性。我会澄清答案。

以上是关于Typescript 索引属性约束检查适用于原始类型但不适用于对象文字?的主要内容,如果未能解决你的问题,请参考以下文章

Typescript中的接口

layaBox---TypeScript---接口

覆盖等于检查类类型或原始 int [重复]

Typescript索引和接口继承

MySQL中的唯一约束

TypeScript:相当于 C# 的用于扩展类的通用类型约束?