类型推断
简介
在这部分,我们将讨论 TypeScript 中的类型推断,我们将讨论在何处以及如何推断类型。
基础
在 TypeScript 中,在没有显式标注类型的情况下,有很多地方使用类型推断来提供类型信息。例如。
let x = 3;
变量 x 的类型将被推断为 number,初始化变量和成员、设置参数默认值、以及确定函数返回类型时会发生这种推断。
大多数情况下,类型推断都比较直观。下面部分,我们将探讨类型推断的一些特殊情况。
最佳通用类型
当类型推断的目标是多个表达式的时候,这些表达式的类型会用于计算“最佳通用类型”,例如。
let x = [0, 1, null];
要推断上面变量 x 的类型,我们必须要考虑数组中的每个元素。这里会给出两种类型: number 和 null,最佳通用类型算法会考虑每种候选类型,并选择与所有其他候选类型兼容的类型。
因为必须从提供的候选类型中选择最佳通用类型,在某些情况下,类型具有相同的结构,但是没有一个候选类型是所有候选类型的父类型。例如。
let zoo = [new Rhino(), new Elephant(), new Snake()];
理想情况下,我们希望变量 zoo 被推断为 Animal[],但数组中没有任何一个元素是严格意义上的 Animal 类型,所以没有办法通过数组元素推断变量 zoo 的类型。为了解决这个问题,当没有一种类型是所有其他候选类型的父类型时,就需要显式声明变量的类型。
let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];
当还是没有办法确认最佳通用类型时,变量的类型就会是联合类型数组 (Rhino | Elephant | Snake)[]。
上下文类型推断
在 TypeScript 中,类型推断也可以以其他方式工作。那就是“上下文类型推断”。当表达式的类型由其所处位置暗示时,便会发生上下文类型推断。例如。
window.onmousedown = function(mouseEvent) {
console.log(mouseEvent.button); //<- OK
console.log(mouseEvent.kangaroo); //<- Error!
};
类型检查器使用 Window.onmousedown 函数的类型来推断右侧表达式的类型,当这样做时,能够推断出 mouseEvent 参数的类型,该类型具有 button 属性,但没有 kangaroo 属性。
TypeScript 也可以在其他上下文中完成类型推断。
window.onscroll = function(uiEvent) {
console.log(uiEvent.button); //<- Error!
}
因为上面这个函数已经赋值给 Window.onscroll,TypeScript 就已经知道 uiEvent 的类型是 UIEvent,而不是上面那个例子中的 MouseEvnet,UIEvent 类型的实例是没有 button 属性的,所以 TypeScript 抛出异常。
如果函数不在上下文的合理位置,函数的参数类型默认就是 any,TypeScript 不会提示任何错误(除非你使用 --noImplicitAny 选项)。
const handler = function(uiEvent) {
console.log(uiEvent.button); //<- OK
}
我们还可以显式地将类型信息提供给函数的参数,以覆盖上下文类型。
window.onscroll = function(uiEvent: any) {
console.log(uiEvent.button); //<- Now, no error is given
};
然而,这里代码将输出 undefined,因为 uiEvent 没有 button 属性。
上下文类型推断适用于很多场景,常见的情况包括函数调用的参数、变量的右侧赋值、类型断言、对象成员、数组字面量和返回值等。上下文类型还可以作为最佳通用类型的候选类型。例如。
function createZoo(): Animal[] {
return [new Rhino(), new Elephant(), new Snake()];
}
这个例子中,最佳通用候选类型包括:Animal、Rhino、Elephant 和 Snake。Animal 会被最佳通用类型算法选中。