文章首發javascript
原文: Interface vs Type alias in TypeScript 2.7html
譯者注:java
常常有人在網上,在工做中,甚至在滑板公園詢問我,在Typescript中定義編譯時類型的類型別名和interface有什麼區別。ios
我之前作的第一件事就是讓他們去看Typescript的手冊。。。git
不幸的是在大多數時候,他們不能找到他們想要找到的東西(隱藏在「高級類型」部分)。即便你能找到它,這個信息描述的是過期的(描述的行爲指針對Typescript@2.0.x版本)。github
好消息各位!你沒必要在看了,這篇文章是關於什麼時候使用interface或類型別名的最新描述和風格指南。typescript
"類型別名 能夠和interface關鍵字同樣,然而他們有一些細微的差異。"
複製代碼
這是對的bash
*interface*可以建立一個新的類型,*類型別名*不能建立一個新的類型
--例如:錯誤信息不能使用*類型別名*
複製代碼
這是不對的!(自從Typescript 2.1開始)函數
咱們分別經過類型別名和interface定義編譯時類型Point,而且實現使用interface和類型別名的類型參數實現兩種getRectangleSquare
。ui
類型別名 和 interface 聲明的Point
使用類型別名和interface定義getRectangleArea函數的參數
類型別名 和 interface聲明的有相同的錯誤
兩個相同的錯誤以下:
// TS Error:
// Interface:
Argument of type '{ x: number; }' is not assignable to parameter of type 'PointInterface'. Property 'y' is missing in type '{ x: number; }'.
// Type alias:
Argument of type '{ x: number; }' is not assignable to parameter of type 'PointType'. Property 'y' is missing in type '{ x: number; }'.
複製代碼
"第二個更加劇要的重要的區別是類型別名不能被繼承或者實現"
複製代碼
這個一樣也是錯的
咱們可以經過一個interface繼承類型別名:
interface 繼承類型別名
或者咱們使用類型別名來實現類:
類實現類型別名。
或者一個類可以實現繼承了類型別名的interface
ThreeDimension 繼承了PointType。PointType是類型別名聲明的。
咱們也能經過組合類型別名和interface去實現類。
class 實現了interface和類型別名
"3. 類型別名 不能繼承/實現 其餘的類型別名"
複製代碼
固然這個也是錯誤的
類型別名能經過交叉類型運算符**&**擴展interface或者任意有效的Typescript類型(它相似字典或者javascript對象,非原始類型)。
類實現了具備交叉類型的*類型別名*
咱們也能利用映射類型實現interface和類型別名的各類類型轉換。
讓咱們經過Partial映射類型把Shape和Perimeter變爲可選的。
類實現了經過交叉運算符和類型映射定義的*類型別名*。`perimeter()`和`area()`是可選的以致於咱們不必在類中去實現他們。
弱類型檢測也正常工做
弱類型檢測定期望的同樣工做。
你可能偶爾想要定義一個能夠充當一個具備額外屬性對象或函數的對象。
咱們這裏討論的是定義函數(可執行對象),和該函數的靜態屬性。
當與第三方庫進行交互時,能夠看到這種模式,這充分描述了類型的「全貌」
混合類型的定義和實現。
它和類型別名同樣工做!
經過類型別名定義混合類型。
可是有一個很是微妙的不一樣。你將要在IDE中獲得具體的類型信息去代替Counter類型。
使用類型別名和混合類型的interface的區別。
一般一個好的實踐,是將咱們的混合定義分爲兩個部分:
可調用對象(函數)類型別名
靜態屬性對象描述
這將要在編譯的時候觸發一個錯誤:
第一點不一樣——聯合運算符定義的類型不能被實現
這徹底有道理!一個圖紙不能實現兩個結構類型中的一個,因此在這方面沒有什麼好驚訝的。
複製代碼
類型別名聯合使用用於定義對象是有意義而且有效的。因此下面會在編譯時報一個錯誤,由於對象必須去定義perimeter()
和area()
兩個中的一個。
聯合類型——正確的使用對象字面量
第二個不一樣——聯合定義類型不能被`interface`繼承
一樣,這個類的實現類似, interface
是一個「靜態」圖紙——它不能實現兩個結構中的一個,因此它不能被聯合類型合併繼承。
interface有聲明合併,可是類型別名沒有。
什麼是聲明合併?
你能定義屢次相同的interface,這些定義將要合併爲一個。
聲明合併
這種方式對於類型別名就不成立,由於類型別名是獨一無二的實體(對於全局和模塊域)。
第三個不一樣——類型別名不支持聲明合併。
當咱們爲沒有使用Typescript創做的庫寫第三方環境定義的時候,經過interface的聲明合併是很是重要的,若是一些定義沒有的話,使用者能夠選擇性的擴展它。
若是咱們的庫是使用Typescript寫的,而且自動生成環境定義則一樣使用。
這是惟一的用例,你應該老是使用interface而不是類型別名。
通常的,你要使用的一致就能夠(不管使用類型別名仍是interface),就我我的而言,我仍是推薦使用類型別名:
type Props = {}
// BAD
interface Props extends OwnProps, InjectedProps, StoreProps {}
type OwnProps = {...}
type StoreProps = {...}
// GOOD
type Props = OwnProps & InjectedProps & StoreProps
type OwnProps = {...}
type StoreProps = {...}
複製代碼
在這遍文章中咱們學到了在Typescript 2.7中interface和類型別名的不一樣。
有了這個,咱們得出在特定的場景中應該如何去定義編譯類型的結論。
讓咱們來回顧一下: