在 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
可由最佳共用類型演算法選取。