类型推导

Type Inference

简介

本章节将涵盖TypeScript中的类型推导。也就是说,这里将讨论类型在何处及如何被推导。

类型推导基础

在TypeScript中,有好几个地方都使用到类型推导,来处理那些没有显式类型注解(explicit type annotation)时,用于提供类型的信息。比如,在下面的代码中:

let x = 3;

变量i的类型,就被推导为number。这种推导,是在对变量及成员进行初始化、参数默认值的设置(setting parameter default values),以及确定函数返回值类型等期间发生的。

大多数情况下,类型推导都是直截了当的。在下面部分中,将对类型是如何进行推导的细微之处,进行探讨。

最优通用类型(Best common type)

当类型推导是从几个表达式生成的时,这些表达式的类型,就被用作计算出一个“最优通用类型”。比如:

let x = [0, 1, null];

为推导出上面示例中x的类型,就必须考虑各个数组元素的类型。这里给到的该数组类型有两个选择:numbernull最优通用类型算法 就对各个候选类型加以考虑,并选取那个兼容所有其它候选项的类型( the best common type algorithm considers each candidate type, and picks the type that is compatible with all the other candidates)。

因为必须要从所提供的候选类型选出最优通用类型,那么就有着某些候选类型共享一个通用结构,却并存在一个作为所有候选类型超集的类型的情况。比如:

let zoo = [new Rhino(), new Elephant(), new Snake()];

理想情况下,可能希望将zoo推导为一个Animal[],但因为该数组中没有对象是严格的Animal类型,所以无法做出有关该数组元素类型的推导。为了纠正这一点,就要在没有一种类型是其它候选类型的超类型时,提供显式地提供一个类型:

let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];

而在找不到最佳通用类型时,推导结果就是联合数组类型(the union array type),(Rhino | Elephant | Snake)[]

上下文的类型(Contextual Type)

在TypeScript中,类型推导在某些情况下还以“其它方向”起作用(Type inference also works in "the other direction" in some cases in TypeScript)。这就是所谓的“上下文的赋予类型(contextual typing)”。上下文类型赋予是在某个表达式的类型由其所处位置所决定时,发生的。比如:

window.onmousedown = function (mouseEvent) {
    console.log(mouseEvent.button); //<- Error
};

为了从上面的代码中检查出错误,TypeScript的类型检查器使用了window.onmousedown函数的类型,类推导该赋值语句右侧的函数表达式的类型(For the code above to give the type error, the TypeScript type checker used the type of the window.onmousedown function to infer the type of the function expression on the right hand side of the assignment)。在其这样做的时候,就能够推导出mouseEvent参数的类型。而假如该函数表达式并不是在一个上下文类型赋予位置(not in a contextually typed position),那么参数mouseEvent将有着类型any,从而不会出现任何错误。

而如果上下文类型赋予的表达式(the contextually typed expression)包含了显式的类型信息,那么上下文类型将被忽略。也就是像下面这样写上面的示例:

window.onmousedown = function (mouseEvent: any) {
    console.log(mouseEvent.button); // <- Now, no error is given
};

参数上带有显式类型注记的函数表达式,将覆盖上下文类型。而一旦这样做,就不会报出错误了,因为应用没有上下文类型特性。

在很多情况下,上下文类型赋予都得以应用。常见的包括函数调用的参数、赋值语句的右侧、类型断言、对象的成员与数组字面值,以及返回语句等(Contextual typing applies in many cases. Common cases include arguments to function calls, right hand sides of assignments, type assertions, members of object and array literals, and return statements)。在最佳通用类型中,上下文类型也扮演了一种候选类型。比如:

function createZoo(): Animal[] {
    return [new Rhino(), new Elephant(), new Snake()];
}

在此示例中,最佳通用类型有着四种候选类型的集合:AnimalRhinoElephant以及Snake。其中Animal可能会被最佳通用类型算法选中。

Last change: 2023-03-28, commit: 4e70b88