在 TypeScript 中,有許多地方會在沒有顯式型別註釋的情況下使用型別推論來提供型別資訊。例如,在這段程式碼中
tsTryletx = 3;
變數 x 的型別被推斷為 number。這種推斷髮生在初始化變數和成員、設定引數預設值以及確定函式返回值型別時。
在大多數情況下,型別推論非常直接。在接下來的章節中,我們將探索型別推論方式中的一些細微差別。
最佳通用型別
當從多個表示式進行型別推論時,這些表示式的型別會被用來計算一個“最佳通用型別”。例如:
tsTryletx = [0, 1, null];
為了推斷上述示例中 x 的型別,我們必須考慮陣列中每個元素的型別。這裡我們為陣列型別提供了兩種選擇:number 和 null。最佳通用型別演算法會考慮每個候選型別,並選出相容所有其他候選型別的型別。
由於最佳通用型別必須從提供的候選型別中選出,有些情況下型別共享共同結構,但沒有一個型別是所有候選型別的超型別。例如:
tsTryletzoo = [newRhino (), newElephant (), newSnake ()];
理想情況下,我們可能希望 zoo 被推斷為 Animal[],但因為陣列中沒有嚴格型別為 Animal 的物件,所以我們不對陣列元素型別進行推斷。若要修正此問題,請在沒有一個型別是所有其他候選型別的超型別時顯式提供型別:
tsTryletzoo :Animal [] = [newRhino (), newElephant (), newSnake ()];
當找不到最佳通用型別時,最終推斷結果為聯合陣列型別:(Rhino | Elephant | Snake)[]。
上下文型別
在某些情況下,TypeScript 中的型別推論也會向“相反方向”工作。這被稱為“上下文型別”。上下文型別發生在表示式的型別由其所處位置暗示時。例如:
tsTrywindow .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 也足夠智慧,可以在其他上下文中推斷型別:
tsTrywindow .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 選項)。
tsTryconsthandler = function (uiEvent ) {console .log (uiEvent .button ); // <- OK};
我們還可以顯式地為函式引數提供型別資訊,以覆蓋任何上下文型別:
tsTrywindow .onscroll = function (uiEvent : any) {console .log (uiEvent .button ); // <- Now, no error is given};
然而,這段程式碼會記錄 undefined,因為 uiEvent 沒有名為 button 的屬性。
上下文型別適用於許多情況。常見的情況包括函式呼叫的引數、賦值的右側、型別斷言、物件和陣列字面量的成員以及返回語句。上下文型別也會作為最佳通用型別的候選型別。例如:
tsTryfunctioncreateZoo ():Animal [] {return [newRhino (), newElephant (), newSnake ()];}
在這個例子中,最佳通用型別有四個候選者:Animal、Rhino、Elephant 和 Snake。其中,Animal 可以被最佳通用型別演算法選中。