任何类型都可以转换为Typescript中的数字映射

时间:2018-10-15 14:11:31

标签: typescript

看来,打字稿允许将任何类型的键强制转换为键类型为number的地图。这是示例代码:

type NumberMap = {
  [key: number]: string
}

type AnyType = {
  foo: string
  bar: boolean[]
}

const anyTypeObj: AnyType = { foo: "foo", bar: [false] }

const numberMap: NumberMap = anyTypeObj

我希望在尝试将AnyType分配给NumberMap时,最后一行会给我一个类型错误,但事实并非如此。但是,将对象文字直接分配给类型为NumberMap的变量可以按预期工作,并且会导致类型错误:

const numberMap: NumberMap = { foo: "foo", bar: [false] }

这里是link,上面的代码在打字稿游乐场上显示。

为什么打字稿允许将任何类型的对象强制转换为NumberMap? 类型{ [key: number]: string }有什么特别之处可以使其表现为这种方式?

1 个答案:

答案 0 :(得分:3)

当将对象文字分配给变量时,Typescript会做一些额外的检查。这称为excess property checking。想法是,将对象文字分配给类型不完全相同的变量的变量很可能是错误的。另一方面,不完全匹配的重分配和参数值在Javascript中很常见,因此,如果右侧表达式不是对象文字,只要值的类型与变量的类型兼容,就允许不精确的分配。

在您的示例中,anyTypeObjNumberMap兼容。您可以将anyTypeObj视为空的NumberMapNumberMap的合同规定,如果您通过数字键访问属性,则结果将为字符串。 anyTypeObj没有数字键,因此在任何情况下都是不正确的。

请注意,将anyTypeObj分配给numberMap后,您将无法再通过foo访问barnumberMap属性,因为{ {1}}类型不会声明这些属性。

编辑:margaretkru提出了以下问题:

  

为什么NumberMap并没有强制要求对象上的所有键都必须是{ [key: number]: string }类型和值number?因为string具有带有anyTypeObj键的属性,所以在这种情况下,我期望转换为string会失败。

我的解释是,变量可以接受类型为compatible且类型为变量的任何值。我从子类型的角度考虑兼容性。例如:

NumberMap

即使const a: Animal = new Cow() Cow的子类,即使AnimalCow的子类也可以。

在面向对象的语言中,类型要么是类,要么是接口,并且如果Animal显式扩展或实现B,则类型A仅被视为B的子类型。但是某些语言(包括Typescript)具有更一般的看法。 “类型”的最一般定义是对满足某些条件的一组可能值的描述。如果A描述的值集是B描述的值的子集,则AB的子类型。 A是否在其定义中命名B无关紧要。

A描述了其数字属性都具有类型NumberMap的所有对象的集合。

stringAnyType的子类型,因为其所有数字属性都具有类型NumberMap。 (这是微不足道的,因为string没有数字属性)。 AnyType上的字符串属性确实会干扰AnyType的合同,因为NumberMap并没有说明字符串属性。