跳到主要内容

TypeScript 类型推断

简介:在本教程中,你将了解 TypeScript 中的类型推断。

类型推断描述了当你没有明确指定数据类型时,TypeScript 在何处以及如何推断类型。

基本类型的推断

当你声明一个变量时,你可以使用类型注释来显式地指定它的类型。例如:

let counter: number;

但是,如果将 counter 变量初始化为数字,TypeScript 会推断它的类型为 number。例如:

let counter = 0;

它等效于以下语句:

let counter: number = 0;

同样,当你为函数参数赋值时,TypeScript 会将参数的类型推断为默认值的类型。例如:

function setCounter(max=100) {
// ...
}

在此示例中,TypeScript 将 max 参数的类型推断为 number

同样,TypeScript 将以下 increment() 函数的返回类型推断为 number

function increment(counter: number) {
return counter++;
}

它与以下内容效果相同:

function increment(counter: number) : number {
return counter++;
}

最通用类型算法

请看如下赋值语句:

let items = [1, 2, 3, null];

为了推断 items 变量的类型,TypeScript 需要考虑数组中每个元素的类型。

它使用最通用类型算法来分析每个候选类型,并选择与所有其他候选类型兼容的类型。

对于如上的例子,TypeScript 选择数字数组类型( number[] ) 作为最通用的类型。

如果将字符串添加到 items 数组,TypeScript 会将它的类型推断为数字和字符串组成的数组:(number | string)[]

let items = [0, 1, null, 'Hi'];

当 TypeScript 找不到最通用类型时,它会返回联合数组类型。例如:

let arr = [new Date(), new RegExp('\d+')];

在此示例中,TypeScript 将 arr 的类型推断为 (RegExp | Date)[]

基于上下文的类型推断

TypeScript 根据变量的位置来推断它们的类型。这种机制称为上下文类型推断。例如:

document.addEventListener('click', function (event) {
console.log(event.button); //
});

在这个例子中,TypeScript 知道 event 参数是 MouseEvent 的实例,因为是 click 事件。

但是,当你将 click 事件更改为 scroll 事件时,TypeScript 会报错:

document.addEventListener('scroll', function (event) {
console.log(event.button); // compiler error
});

错误:

Property 'button' does not exist on type 'Event'.(2339)

TypeScript 知道此时 eventUIEvent 的实例,而不是 MouseEvent 的实例。并且 UIEvent 没有 button 属性,因此,TypeScript 会抛出一个错误。

你会在多种场景下发现上下文类型推断,例如函数调用时的传参、类型声明、对象的属性和数组的元素,return 语句以及赋值语句。

类型推断与类型注解

下面显示类型推断和类型注释之间的区别:

类型推断类型注解
TypeScript 猜测类型你明确地告诉 TypeScript 类型

那么,什么时候分别使用类型推断和类型注解呢?

在实践中,你应该始终尽可能多地使用类型推断。同时,在以下情况下使用类型注释:

  • 当你声明一个变量并稍后为其赋值时。
  • 当你想要一个无法推断的变量时。
  • 当一个函数返回 any 类型而你需要明确它的数值类型时。

概括

  • 当你初始化变量、设置参数默认值和决定函数返回类型时,就会发生类型推断。
  • TypeScript 使用最通用类型算法来选择与所有变量兼容的最佳候选类型。
  • TypeScript 还根据变量的位置使用上下文类型推断来推断变量的类型。