在 TypeScript 中,类型推断用于在没有显式类型注解的情况下提供类型信息。例如,在以下代码中
tsTry
letx = 3;
x
变量的类型被推断为 number
。这种推断发生在初始化变量和成员、设置参数默认值以及确定函数返回值类型时。
在大多数情况下,类型推断是直观的。在接下来的部分中,我们将探讨类型推断中的一些细微差别。
最佳通用类型
当从多个表达式进行类型推断时,这些表达式的类型将用于计算“最佳通用类型”。例如,
tsTry
letx = [0, 1, null];
为了推断上面示例中 x
的类型,我们必须考虑每个数组元素的类型。这里我们有两个关于数组类型的选择:number
和 null
。最佳通用类型算法会考虑每个候选类型,并选择与所有其他候选类型兼容的类型。
由于最佳通用类型必须从提供的候选类型中选择,因此在某些情况下,类型具有共同的结构,但没有一个类型是所有候选类型的超类型。例如,
tsTry
letzoo = [newRhino (), newElephant (), newSnake ()];
理想情况下,我们可能希望将 zoo
推断为 Animal[]
,但由于数组中没有严格类型为 Animal
的对象,因此我们不会对数组元素类型进行任何推断。为了纠正这一点,当没有一个类型是所有其他候选类型的超类型时,请显式提供类型。
tsTry
letzoo :Animal [] = [newRhino (), newElephant (), newSnake ()];
当找不到最佳通用类型时,推断结果将是联合数组类型 (Rhino | Elephant | Snake)[]
。
上下文类型
在某些情况下,类型推断在 TypeScript 中也以“反方向”工作。这被称为“上下文类型”。上下文类型发生在表达式的类型由其位置隐含时。例如,
tsTry
window .onmousedown = function (mouseEvent ) {console .log (mouseEvent .button );Property 'kangaroo' does not exist on type 'MouseEvent'.2339Property 'kangaroo' does not exist on type 'MouseEvent'.console .log (mouseEvent .); kangaroo };
这里,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 eventsinterface GlobalEventHandlers {onmousedown: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;// ...}
TypeScript 足够智能,可以在其他上下文中推断类型。
tsTry
window .onscroll = function (uiEvent ) {Property 'button' does not exist on type 'Event'.2339Property 'button' does not exist on type 'Event'.console .log (uiEvent .); button };
基于上述函数被分配给 `Window.onscroll` 的事实,TypeScript 知道 `uiEvent` 是一个 UIEvent,而不是像之前示例中的 MouseEvent。`UIEvent` 对象不包含 `button` 属性,因此 TypeScript 会抛出错误。
如果此函数不在上下文类型的位置,则函数的参数将隐式具有类型 `any`,并且不会发出错误(除非您使用 noImplicitAny
选项)。
tsTry
consthandler = function (uiEvent ) {console .log (uiEvent .button ); // <- OK};
我们也可以显式地为函数的参数提供类型信息来覆盖任何上下文类型。
tsTry
window .onscroll = function (uiEvent : any) {console .log (uiEvent .button ); // <- Now, no error is given};
但是,这段代码将记录 `undefined`,因为 `uiEvent` 没有名为 `button` 的属性。
上下文类型在许多情况下适用。常见情况包括函数调用的参数、赋值的右侧、类型断言、对象和数组文字的成员以及返回值。上下文类型也充当最佳通用类型中的候选类型。例如
tsTry
functioncreateZoo ():Animal [] {return [newRhino (), newElephant (), newSnake ()];}
在这个例子中,最佳通用类型有一组四个候选者:`Animal`、`Rhino`、`Elephant` 和 `Snake`。在这其中,`Animal` 可以被最佳通用类型算法选择。