「譯」TypeScript終極指南四:對象、函數類型約束

原文來自 The Definitive TypeScript Guide -(https://www.sitepen.com/blog/2018/10/29/update-the-definitive-typescript-guide/)

對象類型

除了七種基本類型之外,TypeScript也能輕鬆定義複雜類型(如對象和函數)的類型約束。 正如對象字面量是JavaScript中大多數對象描述的基本一樣,對象類型字面量也是TypeScript中大多數對象類型描述的基本。 其最基礎的形式看起來非常類似於普通的JavaScript對象字面量:

「譯」TypeScript終極指南四:對象、函數類型約束

在此例中,變量point被定義為具有x和y屬性的對象。 請注意,與JavaScript對象字面量不同,對象類型字面量使用分號而不是逗號分隔字段。

當TypeScript比較兩種不同的對象類型來決定它們是否匹配時,它是從結構上來檢查的。 這意味著,不是通過檢查它們是否都繼承相同的基本約束對象來比較類型(如instanceof),而是通過每個對象的屬性來比較的。 只要提供的對象擁有對所賦予的變量的約束所需的所有屬性,它們就被認為是兼容的(儘管對象文字賦值被更嚴格地視為特殊情況):

「譯」TypeScript終極指南四:對象、函數類型約束

為了減少類型重複,typeof運算符也可用於定義類型約束。 例如,我們要添加一個point2變量,不是必須非得這樣寫:

「譯」TypeScript終極指南四:對象、函數類型約束

我們可以使用typeof簡單地引用point的類型:

「譯」TypeScript終極指南四:對象、函數類型約束

這種機制有助於減少引用相同類型約束所需的代碼量,但在TypeScript中還有另一種更強大的抽象用於複用對象類型:接口(interfaces)。 接口本質上是一個命名的對象類型字面量。 更改上一個示例使用接口將如下所示:

「譯」TypeScript終極指南四:對象、函數類型約束

這裡的改動使得在代碼中的多個位置可以重複使用Point類型,而無需一遍又一遍地重新定義類型的詳細信息。 接口還可以使用extends關鍵字來擴展其他接口或類,以便於從簡單類型中組成更復雜的類型:

「譯」TypeScript終極指南四:對象、函數類型約束

在此例中,生成的Point3d類型將包含Point接口中的x和y屬性以及新定義的z屬性。對象中的方法和屬性也可以指定為可選型,與指定函數的可選參數方式相同:

「譯」TypeScript終極指南四:對象、函數類型約束

在這裡我們將z屬性設置為可選,類型檢查的結果將如下所示:

「譯」TypeScript終極指南四:對象、函數類型約束

到目前為止,我們已經看到了對象類型的屬性,但尚未提到如何向對象中添加方法。 因為函數是JavaScript中的第一等對象,它可以使用屬性語法,但TypeScript中還提供了一種用於定義方法的簡寫語法,這使得我們之後使用類的時候會變得非常方便:

「譯」TypeScript終極指南四:對象、函數類型約束

在這個例子中,我們在Point接口中添加了一個toGeo方法,該方法不接受任何參數並返回另一個Point對象。 與屬性一樣,通過在方法名稱後面添加問號,也可以使得方法成為可選方法:

「譯」TypeScript終極指南四:對象、函數類型約束

給對象一個索引簽名能使它作為哈希映射或有序列表來使用,從而確保對象中任意鍵的獨特性:

「譯」TypeScript終極指南四:對象、函數類型約束

在這個例子中,我們定義了一個可以設置任何鍵的類型,只要賦予的值是Point類型就行。 與在JavaScript中一樣,只能使用字符串或數字作為索引簽名的類型。

對於沒有索引簽名的對象類型,TypeScript將只允許在類型上設置顯性定義的屬性。 如果嘗試賦值給類型上不存在的屬性,則會出現編譯器報錯。 但有時,你確實想要在沒有索引簽名的情況下向對象添加動態屬性。 為此,你可以簡單地使用數組表示法來設置對象的屬性:a ['foo'] ='foo'。但請注意,使用此方法會使這些屬性的類型系統失敗,因此只能將此作為最後的手段來使用。

Typescript 2.7增加了在類型上具有常量命名屬性的功能。 這意味著可以使用常量字符串、數字或符號定義接口。

「譯」TypeScript終極指南四:對象、函數類型約束

元組類型

雖然JavaScript本身沒有元組,但TypeScript可以使用數組模擬元組類型。 如果你想要將點存儲為一個(x,y,z)元組而不是一個對象,可以通過在變量上指定元組類型來完成:

「譯」TypeScript終極指南四:對象、函數類型約束

TypeScript 3.0通過允許rest和spread表達式以及可選元素為元組類型添加了更好的支持:

「譯」TypeScript終極指南四:對象、函數類型約束

函數類型

因為JavaScript中的函數是第一等對象,所以對象類型字面量語法也可用來說明函數這一個對象。 為此,使用與上面toGeo相同的語法,但方法名稱留空:

「譯」TypeScript終極指南四:對象、函數類型約束

這裡,printPoint被定義為接受一個獲取point對象並返回一個字符串的函數。

由於函數在JavaScript中非常常見,因此TypeScript中有一種特定的函數類型簡寫語法,可用於定義具有單個調用簽名的函數:

「譯」TypeScript終極指南四:對象、函數類型約束

注意,這裡使用了來自ES2015箭頭函數的箭頭(=>)來定義函數的返回類型。 在對象類型字面量、接口或類中約束方法的返回類型時使用冒號(:),而這裡卻用箭頭來約束函數的返回類型, 起初這有點令人困惑,但是當你使用TypeScript時,你會發現很容易就能知道應該使用兩個中的哪個。 例如,在上面的示例中,使用冒號看起來是錯誤的,因為它會在句中直接產生兩個冒號:let printPoint: (point: Point): string。

現在我們知道了函數類型語法,讓我們回到Point定義,將toGeo定義為屬性而不是方法如下所示:

「譯」TypeScript終極指南四:對象、函數類型約束

通過將new關鍵字放在函數類型之前能使函數作為構造函數:

「譯」TypeScript終極指南四:對象、函數類型約束

在此例中,賦給Point或ShorthandEquivalent的任何函數都需要是創造Point對象的構造函數。

因為對象字面量語法允許我們將對象定義為函數,所以也可以使用靜態屬性或靜態方法來定義函數類型(例如JavaScript中的String函數,它擁有靜態方法String.fromCharCode):

「譯」TypeScript終極指南四:對象、函數類型約束

在這裡,我們定義Point為接受一個構造函數,並且該構造函數還需要具有Point.fromLinear和Point.fromGeo靜態方法。 實際上能執行此操作的唯一方法就是定義一個實現Point的類,並具有fromLinear和fromGeo靜態方法。當我們深入討論classes時,我們將會看到如何做到這一點。

未完待續


分享到:


相關文章: