在这一节,我们将介绍TypeScript中的类型推断。我们将会讨论类型推断需要在何处用到以及如何推断。
基础
在TypeScript中,在几个没有明确指定类型注释的地方将会使用类型推断来提供类型信息。
var x = 3;
变量"x"的值被推断为number。这种推断发生在变量或者成员初始化、设置参数默认值、决定函数返回类型的时候。
最佳公共类型
当需要从多个表达式中进行类型推断的时候,这些表达式的类型将会用来推断出一个"最佳公共类型"。例如:
var x = [0, 1, null];
要想推断出什么例子中"x"的类型,我们需要考虑每个数组元素的类型。这里,我们给出了两个数组类型的选择:number和null。最佳公共类型算法要求考虑到所有候选的类型,并选择出与所有候选类型兼容的类型。(这里的类型可为Array<number>)
由于最佳公共类型是从提供的候选类型中选择的,有些情况下,候选类型共享一个共同类型,但没有任何一个类型是所有候选类型的父类型。例如:
class Animal { name:string; constructor(theName: string) { this.name = theName; } } class Snake extends Animal{ constructor(name: string) { super(name); } } class Elephant extends Animal{ constructor(name: string) { super(name); } } class Rhino extends Animal { constructor(name: string) { super(name); } } var zoo = [new Rhino(), new Elephant(), new Snake()]; // 这里三个成员的类型分别为:Rhino、Elephant、Snake 他们是最佳公共类型的候选类型,Animal是他们的super type(译为父类型)
理想情况下,我们可能希望zoo被推断为Animal[]类型,但是因为数组中没有任何对象是严格的Animal类型,我们便不能做出推断。为了解决这个问题,当不能推断出所有候选类型的父类型的时候,我们需要明确的提供类型。
var zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];
当没有最佳公共类型的时候,推断的结果是产生一个空对象,{}。因为这个类型不含任何成员,对于其任何属性的访问都会导致错误。这种结果依然允许我们在忽略类型的方式中使用对象,但在保障类型安全的前提下,该对象的类型不能被隐式的确定。
上下文(语境)类型
在TypeScript中,类型推断在某些情况下也存在于"其他方面"。这被称为"上下文归类"。上下文归类发生在当一个表达式的类型在其所在的上下文中被隐式的指定的时候。例如:
window.onmousedown = function(mouseEvent) { console.log(mouseEvent.buton); //<- 编译时抛出错误 };
上面的代码将会给出一个类型错误,TypeScript的类型检查器使用Window.onmousedown函数的类型来推断右边的函数表达式类型。当它这么做的时候,便能够推断出参数mouseEvent的类型。 如果这个表达式不在可进行上下文归类的位置,参数mouseEvent 需要给定一个any类型,这样就不会出现错误了。
如果需要上下文归类的表达式内容中包含明确的类型信息,则会忽略上下文归类。我们重写上面的例子:
window.onmousedown = function(mouseEvent: any) { console.log(mouseEvent.buton); //<- 现在不会报错了 };
参数明确指定类型的函数表达式将会忽略上下文归类。经过这样的处理就不会报错了,因为没有应用到上下文归类。
上下文归类可应用于许多场景。常见的场景包括函数调用的参数、赋值的等号右边表达式、类型确定、对象成员和数组字面量、返回值语句。上下文类型也作为最佳公共类型的候选类型。例如:
function createZoo(): Animal[] { return [new Rhino(), new Elephant(), new Snake()]; }
在这个例子中,最佳公共类型有四个候选类型:Animal,Rhino,Elephant,和Snake。其中,Animal可以作为最佳公共类型。
形式有点像数学中的求最小公倍数...