在這一節,我們將介紹TypeScript中的類型推斷。我們將會討論類型推斷需要在何處用到以及如何推斷。
基礎
在TypeScript中,在幾個沒有明確指定類型注釋的地方將會使用類型推斷來提供類型信息。
var x = 3;
變量"x"的值被推斷為number。這種推斷發生在變量或者成員初始化、設置參數默認值、決定函數返回類型的時候。
最佳公共類型
當需要從多個表達式中進行類型推斷的時候,這些表達式的類型將會用來推斷出一個"最佳公共類型"。例如:
var x = [0, 1, null];
要想推斷出什么例子中"x"的類型,我們需要考慮每個數組元素的類型。這里,我們給出了兩個數組類型的選擇:number和null。最佳公共類型算法要求考慮到所有候選的類型,並選擇出與所有候選類型兼容的類型。(這里的類型可為Array<number>)
由於最佳公共類型是從提供的候選類型中選擇的,有些情況下,候選類型共享一個共同類型,但沒有任何一個類型是所有候選類型的父類型。例如:
class Animal { name:string; constructor(theName: string) { this.name = theName; } } class Snake extends Animal{ constructor(name: string) { super(name); } } class Elephant extends Animal{ constructor(name: string) { super(name); } } class Rhino extends Animal { constructor(name: string) { super(name); } } var zoo = [new Rhino(), new Elephant(), new Snake()]; // 這里三個成員的類型分別為:Rhino、Elephant、Snake 他們是最佳公共類型的候選類型,Animal是他們的super type(譯為父類型)
理想情況下,我們可能希望zoo被推斷為Animal[]類型,但是因為數組中沒有任何對象是嚴格的Animal類型,我們便不能做出推斷。為了解決這個問題,當不能推斷出所有候選類型的父類型的時候,我們需要明確的提供類型。
var zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];
當沒有最佳公共類型的時候,推斷的結果是產生一個空對象,{}。因為這個類型不含任何成員,對於其任何屬性的訪問都會導致錯誤。這種結果依然允許我們在忽略類型的方式中使用對象,但在保障類型安全的前提下,該對象的類型不能被隱式的確定。
上下文(語境)類型
在TypeScript中,類型推斷在某些情況下也存在於"其他方面"。這被稱為"上下文歸類"。上下文歸類發生在當一個表達式的類型在其所在的上下文中被隱式的指定的時候。例如:
window.onmousedown = function(mouseEvent) { console.log(mouseEvent.buton); //<- 編譯時拋出錯誤 };
上面的代碼將會給出一個類型錯誤,TypeScript的類型檢查器使用Window.onmousedown函數的類型來推斷右邊的函數表達式類型。當它這么做的時候,便能夠推斷出參數mouseEvent的類型。 如果這個表達式不在可進行上下文歸類的位置,參數mouseEvent 需要給定一個any類型,這樣就不會出現錯誤了。
如果需要上下文歸類的表達式內容中包含明確的類型信息,則會忽略上下文歸類。我們重寫上面的例子:
window.onmousedown = function(mouseEvent: any) { console.log(mouseEvent.buton); //<- 現在不會報錯了 };
參數明確指定類型的函數表達式將會忽略上下文歸類。經過這樣的處理就不會報錯了,因為沒有應用到上下文歸類。
上下文歸類可應用於許多場景。常見的場景包括函數調用的參數、賦值的等號右邊表達式、類型確定、對象成員和數組字面量、返回值語句。上下文類型也作為最佳公共類型的候選類型。例如:
function createZoo(): Animal[] { return [new Rhino(), new Elephant(), new Snake()]; }
在這個例子中,最佳公共類型有四個候選類型:Animal,Rhino,Elephant,和Snake。其中,Animal可以作為最佳公共類型。
形式有點像數學中的求最小公倍數...