Skip to content
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

类型推断

在 TypeScript 中,当没有显式类型注解时,有多个地方会使用类型推断来提供类型信息。例如,在这段代码中

ts
let 
x
= 3;
Try

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

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

最佳通用类型

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

ts
let 
x
= [0, 1, null];
Try

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

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

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

理想情况下,我们可能希望 zoo 被推断为 Animal[],但因为数组中没有严格属于 Animal 类型的对象,我们不对数组元素类型进行推断。 为了解决这个问题,当没有一种类型是所有其他候选类型的超类型时,显式提供类型:

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

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

上下文类型

在某些情况下,类型推断也以“另一种方向”工作。 这被称为“上下文类型化”。当表达式的类型由其所在位置隐含时,就会发生上下文类型化。例如:

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

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

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

ts
// 声明存在一个名为 'window' 的全局变量
declare var window: Window & typeof globalThis;

// 它被声明为(简化):
interface Window extends GlobalEventHandlers {
  // ...
}

// 它定义了许多已知的事件处理程序
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'.
};
Try

基于上述函数被赋值给 Window.onscroll 的事实,TypeScript 知道 uiEvent 是一个 UIEvent,而不是前一个例子中的 MouseEventUIEvent 对象不包含 button 属性,因此 TypeScript 会抛出错误。

如果此函数不在上下文类型化的位置,该函数的参数将隐式具有 any 类型,并且不会引发错误(除非你使用了 noImplicitAny 选项):

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

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

ts
window
.
onscroll
= function (
uiEvent
: any) {
console
.
log
(
uiEvent
.button); // <- 现在不会报错
};
Try

然而,此代码将打印 undefined,因为 uiEvent 没有名为 button 的属性。

上下文类型化适用于许多情况。 常见的情况包括函数调用的参数、赋值的右侧、类型断言、对象和数组字面量的成员以及返回语句。 上下文类型也作为最佳通用类型的候选类型。例如:

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

在此示例中,最佳通用类型有四个候选:AnimalRhinoElephantSnake。 其中,Animal 可以被最佳通用类型算法选中。