TypeScript - 类型推断
# 1. 基础
在 TypeScript 中,当变量、参数或者返回值没有明确指定类型时,TypeScript 会尝试根据代码中的上下文推断出一个类型,这被称为 类型推断。类型推断帮助开发者简化代码,并且提高代码的可读性和安全性。
示例:
let x = 3;
在上面的示例中,变量 x
被初始化为数字 3
,因此 TypeScript 推断 x
的类型为 number
。这种推断不仅适用于变量的初始化,还包括对象属性的初始化、函数参数的默认值和函数返回值的推断等场景。
大多数情况下,类型推断是直观且正确的,但在某些复杂场景下可能需要更仔细地分析和理解。
# 2. 最佳通用类型
有时候,我们需要从多个表达式中推断出一个最合适的通用类型。TypeScript 会基于这些表达式的类型推断出一个可以兼容所有候选类型的类型,这被称为 最佳通用类型。
示例:
let x = [0, 1, null];
在上面的示例中,数组 x
包含了数字和 null
值。为了推断 x
的类型,TypeScript 需要考虑所有数组元素的类型:number
和 null
。因此,x
被推断为 Array<number | null>
类型,即 number
和 null
的联合类型。
当候选类型共享一个公共结构,但没有一个类型可以作为所有候选类型的超级类型时,TypeScript 可能无法找到一个最佳通用类型。在这种情况下,需要显式地指定类型。
示例:
class Animal {
numLegs: number;
}
class Bee extends Animal {
}
class Lion extends Animal {
}
let zoo = [new Bee(), new Lion()];
2
3
4
5
6
7
8
9
10
11
在上面的示例中,我们希望 zoo
被推断为 Animal[]
类型,但因为数组中的元素是 Bee
和 Lion
类型,TypeScript 无法自动推断出 Animal[]
。我们需要显式地声明预期的类型:
let zoo: Animal[] = [new Bee(), new Lion()];
如果不指定类型,zoo
将被推断为联合数组类型:(Bee | Lion)[]
。通过明确地声明类型,我们可以确保 zoo
是 Animal[]
类型,从而确保代码的正确性和可维护性。
# 3. 上下文类型
在某些情况下,TypeScript 的类型推断会根据代码的上下文来决定类型,这种机制被称为 上下文类型。上下文类型与表达式的位置和预期类型有关。它可以帮助 TypeScript 在特定位置推断出变量或函数参数的类型。
示例:
window.onmousedown = function(mouseEvent) {
console.log(mouseEvent.clickTime); // Error
}
2
3
在这个示例中,TypeScript 会根据 window.onmousedown
的类型来推断右侧函数表达式的参数类型。window.onmousedown
预期接收一个 MouseEvent
类型的参数,因此 TypeScript 推断 mouseEvent
是 MouseEvent
类型。然而,由于 MouseEvent
类型没有 clickTime
属性,因此会产生类型错误。
如果明确为函数表达式的参数添加类型注解,则上下文类型会被忽略:
window.onmousedown = function(mouseEvent: any) {
console.log(mouseEvent.clickTime); // OK
}
2
3
在这个例子中,函数参数 mouseEvent
被显式声明为 any
类型,TypeScript 不再使用上下文类型进行推断,因此不会报错。
上下文类型在多种情况下都会被使用,包括函数参数、赋值表达式的右侧、类型断言、对象成员、数组字面量和返回语句等。它也会被用作确定最佳通用类型的候选类型之一。
示例:
function createZoo(): Animal[] {
return [new Bee(), new Lion()];
}
let zoo = createZoo();
2
3
4
5
在这个例子中,返回语句 [new Bee(), new Lion()]
包含了 Animal
、Bee
和 Lion
三个候选类型。TypeScript 使用上下文类型 Animal[]
来推断最佳通用类型,因此 createZoo
函数返回类型被推断为 Animal[]
。
上下文类型使得 TypeScript 能够根据代码的位置和预期行为进行更加准确的类型推断,从而提高代码的安全性和可读性。