类型推断

在 TypeScript 中,类型推断用于在没有显式类型注解的情况下提供类型信息。例如,在以下代码中

ts
let x = 3;
let x: number
Try

x 变量的类型被推断为 number。这种推断发生在初始化变量和成员、设置参数默认值以及确定函数返回值类型时。

在大多数情况下,类型推断是直观的。在接下来的部分中,我们将探讨类型推断中的一些细微差别。

最佳通用类型

当从多个表达式进行类型推断时,这些表达式的类型将用于计算“最佳通用类型”。例如,

ts
let x = [0, 1, null];
let x: (number | null)[]
Try

为了推断上面示例中 x 的类型,我们必须考虑每个数组元素的类型。这里我们有两个关于数组类型的选择:numbernull。最佳通用类型算法会考虑每个候选类型,并选择与所有其他候选类型兼容的类型。

由于最佳通用类型必须从提供的候选类型中选择,因此在某些情况下,类型具有共同的结构,但没有一个类型是所有候选类型的超类型。例如,

ts
let zoo = [new Rhino(), new Elephant(), new Snake()];
let zoo: (Rhino | Elephant | Snake)[]
Try

理想情况下,我们可能希望将 zoo 推断为 Animal[],但由于数组中没有严格类型为 Animal 的对象,因此我们不会对数组元素类型进行任何推断。为了纠正这一点,当没有一个类型是所有其他候选类型的超类型时,请显式提供类型。

ts
let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];
let zoo: Animal[]
Try

当找不到最佳通用类型时,推断结果将是联合数组类型 (Rhino | Elephant | Snake)[]

上下文类型

在某些情况下,类型推断在 TypeScript 中也以“反方向”工作。这被称为“上下文类型”。上下文类型发生在表达式的类型由其位置隐含时。例如,

ts
window.onmousedown = function (mouseEvent) {
console.log(mouseEvent.button);
console.log(mouseEvent.kangaroo);
Property 'kangaroo' does not exist on type 'MouseEvent'.2339Property 'kangaroo' does not exist on type 'MouseEvent'.
};
Try

这里,TypeScript 类型检查器使用 Window.onmousedown 函数的类型来推断赋值右侧函数表达式的类型。这样做时,它能够推断出 mouseEvent 参数的 类型,该类型确实包含 button 属性,但不包含 kangaroo 属性。

这之所以有效是因为 `window` 的类型中已经声明了 `onmousedown`。

ts
// Declares there is a global variable called 'window'
declare var window: Window & typeof globalThis;
// Which is declared as (simplified):
interface Window extends GlobalEventHandlers {
// ...
}
// Which defines a lot of known handler events
interface GlobalEventHandlers {
onmousedown: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
// ...
}

TypeScript 足够智能,可以在其他上下文中推断类型。

ts
window.onscroll = function (uiEvent) {
console.log(uiEvent.button);
Property 'button' does not exist on type 'Event'.2339Property 'button' does not exist on type 'Event'.
};
Try

基于上述函数被分配给 `Window.onscroll` 的事实,TypeScript 知道 `uiEvent` 是一个 UIEvent,而不是像之前示例中的 MouseEvent。`UIEvent` 对象不包含 `button` 属性,因此 TypeScript 会抛出错误。

如果此函数不在上下文类型的位置,则函数的参数将隐式具有类型 `any`,并且不会发出错误(除非您使用 noImplicitAny 选项)。

ts
const handler = function (uiEvent) {
console.log(uiEvent.button); // <- OK
};
Try

我们也可以显式地为函数的参数提供类型信息来覆盖任何上下文类型。

ts
window.onscroll = function (uiEvent: any) {
console.log(uiEvent.button); // <- Now, no error is given
};
Try

但是,这段代码将记录 `undefined`,因为 `uiEvent` 没有名为 `button` 的属性。

上下文类型在许多情况下适用。常见情况包括函数调用的参数、赋值的右侧、类型断言、对象和数组文字的成员以及返回值。上下文类型也充当最佳通用类型中的候选类型。例如

ts
function createZoo(): Animal[] {
return [new Rhino(), new Elephant(), new Snake()];
}
Try

在这个例子中,最佳通用类型有一组四个候选者:`Animal`、`Rhino`、`Elephant` 和 `Snake`。在这其中,`Animal` 可以被最佳通用类型算法选择。

TypeScript 文档是一个开源项目。帮助我们改进这些页面 通过发送 Pull Request

此页面的贡献者
RCRyan Cavanaugh (51)
OTOrta Therox (17)
DRDaniel Rosenwasser (10)
MHMartin Hanzel (2)
TLATThink Like a Techy (1)
12+

上次更新时间:2024 年 3 月 21 日