类型推断

在本节中,我们将讲到TypeScript中的类型推断(type inference)。我们将详细讲述类型推断发生的时机及发生的方式。

基础

当没有关于类型的明确解释时,有几种情况会使得TypeScript使用类型推断来提供类型信息。举例来说,在下面的代码中:

  1. var x = 3;

变量x的类型会被推断为数字。这种类型推断会发生在下列情况中:初始化变量和成员,设置参数的默认值,在决定函数的返回类型时。

在大多数情况下,类型推断的结果很明了。我们将在后面探索类型推断中一些比较微妙的情况。

最佳通用类型

当我们需要从多个表达式中推断类型时,我们会通过这些表达式计算出一个”最佳通用类型”(”best common type”)。举例来说,

  1. var x = [0, 1, null];

在推断上面例子中x的类型时,我们必须要考虑到数组中每个元素的类型。这里我们有数字和null两种可能,而最佳通用类型算法会根据每种类型的情况,选择一种可以兼容所有其他选择的类型。

因为我们需要从候选类型中选择最佳通用类型,所以也可能出现没有一种类型可以兼容所有类型的情况。举例来说:

  1. var zoo = [new Rhino(), new Elephant(), new Snake()];

在理想的状况下,我们希望zoo 被推断为Animal[]。但是由于数组中并没有Animal类型,我们无法推断出这个数组元素的类型。为了应对这类情况,在数组中如果没有一个元素的类型是其他类型的超类型(super type)的话,我们需要明确提供这个数组的类型:

  1. var zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];

当找不到最佳通用类型时,类型推断的结果就会变成空对象类型,即{}。因为这种类型并没有成员,所以尝试使用该类型上的任何属性都会产生错误。但在这种我们不能隐式推断出对象的类型的情况下,你仍旧能够通过不涉及类型的操作来安全地使用这个对象。

上下文类型

类型推断也能作用于TypeScript中的一些其他情况,其中一种情况便是”上下文类型”(”contextual typing”)。上下文类型作用在“一个表达式的类型可以通过它出现的位置被推断出”的情况下。举例来说:

  1. window.onmousedown = function(mouseEvent) {
  2. console.log(mouseEvent.buton); //<- Error
  3. };

上面的代码会抛出类型错误。因为TypeScript的类型检查器会用Window.onmousedown函数的类型来推断赋值符号另一侧的函数表达式的类型。在这种情况下,它就能推断出mouseEvent参数的类型。如果函数表达式不在这个关乎上下文类型的位置上的话,mouseEvent参数就可以是any类型,而且不会有错误抛出。

如果我们明确地指定了这个表达式的类型的话,上下文类型就会被忽略。我们可以这样来写上面的例子:

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

带有明确类型注释的函数表达式的参数可以覆盖上下文类型。这样就不会有上下文类型其作用,也就不会有错误产生了。

上下文类型可以作用在很多场景中。常见的例子包括:函数调用中的参数,赋值时等号的右边部分,类型判断,对象的成员,迭代数组,以及返回声明(return statements)。上下文类型也会成为最佳通用类型的一个候选类型。举例来说:

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

在这个例子中,我们有四个最佳候选类型:Animal, Rhino, Elephant, and Snake。在这里最佳通用类型算法当然会选择Animal。