Skip to main content

Type Inference

在TypeScript中,类型推断指的是根据分配给变量的值自动确定变量类型的过程。这允许开发者编写更简洁、更易于理解的代码,TypeScript编译器自动推导变量的类型而不用显式指定它们。

在TypeScript中,有很多地方使用类型推断提供类型信息,例如:变量初始化、函数默认参数、函数返回类型等:

// let x: number
let x = 3;

// function test(): number
function test() {
return x
}

最佳公共类型

当从多个表达式推断类型时,这些表达式的类型被用来计算最佳公共类型:

let xx = [1, 2, null] // (number | null)[]
let yy = [1, 2, 'a', {a: 1}] // (string | number | {a: number})[]
let zz = [{}, 1, 2, 'a'] // {}[]

最佳公共类型算法考虑每个值的类型作为候选类型,最终选出一种兼容其它所有类型的类型,而当没有公共类型可选时,大部分时候被推断为联合类型。

因为最佳公共类型必须从提供的候选类型中选择,因此有这样一些情况:几个类型共享公共的结构,但是没有一种类型是其他所有候选类型的超类型时,也就是选不出一种兼容其他所有类型的类型:

class Rhino {}
class Elephant {}
class Snake {}

// (Rhino | Elephant | Snake)[]
const zoo = [new Rhino(), new Elephant(), new Snake()]

如上,我们可能想让类型推断结果为Animal[],但由于数组中没有严格属于Animal类型的对象,因此无法推断出Animal类型。为了纠正这个问题,当没有一个类型是所有其他候选类型的超类型时,则需要显式地提供类型:

class Animal {}
class Rhino extends Zoo{}
class Elephant extends Zoo{}
class Snake extends Zoo{}

const animal: Animal[] = [new Rhino(), new Elephant(), new Snake()

上下文类型推导

上下文类型是指根据表达式的位置隐含地推断表达式的类型。

window.addEventListener('mousedown', (event) => {
console.log(event.button);
// Property 'buton' does not exist on type 'MouseEvent'. Did you mean 'button'?
console.log(event.buton);
}, false)

如上,TypeScript会基于mousedown事件推断其事件处理器函数的参数eventMouseEvent包含button属性,但不存在buton属性。

TypeScript在其他上下文推断中也很智能:

window.addEventListener('scroll', (event) => {
// Property 'button' does not exist on type 'Event'.
console.log(event.button);
}, false)

如上,scroll事件一个UIEvent,而非MouseEventUIEvent对象上不存在button属性,因此TypeScript会抛出错误。

如果事件处理函数并没有在一个上下文的环境中,那么其函数的参数隐式地为any类型:

window.addEventListener('scroll', handler, false)

function handler(e) {
// Parameter 'e' implicitly has an 'any' type.
console.log(e);
}

上下文类型适用于许多情况。 常见的情况包括函数调用的参数、赋值语句的右侧、类型断言、对象和数组字面量的成员以及返回语句。