翻譯: typescript 2.7中interface和type(Interface vs Type alias in TypeScript 2.7)


文章首發javascript


原文: Interface vs Type alias in TypeScript 2.7html

譯者注:java

  • type alias翻譯爲類型別名
  • interface 不作翻譯

image

常常有人在網上,在工做中,甚至在滑板公園詢問我,在Typescript中定義編譯時類型的類型別名interface有什麼區別。ios

我之前作的第一件事就是讓他們去看Typescript的手冊。。。git

不幸的是在大多數時候,他們不能找到他們想要找到的東西(隱藏在「高級類型」部分)。即便你能找到它,這個信息描述的是過期的(描述的行爲指針對Typescript@2.0.x版本)。github

好消息各位!你沒必要在看了,這篇文章是關於什麼時候使用interface類型別名的最新描述和風格指南。typescript

官方的文檔說:

"類型別名 能夠和interface關鍵字同樣,然而他們有一些細微的差異。"
複製代碼

這是對的bash

有什麼不一樣呢

第一個不一樣

*interface*可以建立一個新的類型,*類型別名*不能建立一個新的類型

--例如:錯誤信息不能使用*類型別名*

複製代碼

這是不對的!(自從Typescript 2.1開始)函數

咱們分別經過類型別名interface定義編譯時類型Point,而且實現使用interface類型別名的類型參數實現兩種getRectangleSquareui

image

類型別名 和 interface 聲明的Point

image

使用類型別名和interface定義getRectangleArea函數的參數

image

類型別名 和 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繼承類型別名:

image

interface 繼承類型別名

或者咱們使用類型別名來實現類:

image

類實現類型別名。

或者一個類可以實現繼承了類型別名interface

image

ThreeDimension 繼承了PointType。PointType是類型別名聲明的。

咱們也能經過組合類型別名interface去實現類。

image

class 實現了interface和類型別名

第三個不一樣

"3. 類型別名 不能繼承/實現 其餘的類型別名"
複製代碼

固然這個也是錯誤的

  • 嗯,這個是部分正確的,可是這個表述具備誤導性。

類型別名能經過交叉類型運算符**&**擴展interface或者任意有效的Typescript類型(它相似字典或者javascript對象,非原始類型)。

image

類實現了具備交叉類型的*類型別名*

咱們也能利用映射類型實現interface類型別名的各類類型轉換。

讓咱們經過Partial映射類型把ShapePerimeter變爲可選的。

image

類實現了經過交叉運算符和類型映射定義的*類型別名*。`perimeter()`和`area()`是可選的以致於咱們不必在類中去實現他們。

弱類型檢測也正常工做

image

弱類型檢測定期望的同樣工做。

類型別名 和 interface的混合類型

你可能偶爾想要定義一個能夠充當一個具備額外屬性對象或函數的對象。

咱們這裏討論的是定義函數(可執行對象),和該函數的靜態屬性。

當與第三方庫進行交互時,能夠看到這種模式,這充分描述了類型的「全貌」

混合類型的定義和實現。

它和類型別名同樣工做!

經過類型別名定義混合類型。

可是有一個很是微妙的不一樣。你將要在IDE中獲得具體的類型信息去代替Counter類型。

image

使用類型別名和混合類型的interface的區別。

一般一個好的實踐,是將咱們的混合定義分爲兩個部分:

  • 可調用對象(函數)類型別名

  • 靜態屬性對象描述

image

  • 和最終的Counte類型

image

因此類型別名和interface有什麼區別呢?

1. 不能使用經過類型別名定義聯合類型去實現類

這將要在編譯的時候觸發一個錯誤:

image

第一點不一樣——聯合運算符定義的類型不能被實現

這徹底有道理!一個圖紙不能實現兩個結構類型中的一個,因此在這方面沒有什麼好驚訝的。
複製代碼

類型別名聯合使用用於定義對象是有意義而且有效的。因此下面會在編譯時報一個錯誤,由於對象必須去定義perimeter()area()兩個中的一個。

image

聯合類型——正確的使用對象字面量

2. 不一樣經過類型別名定義的聯合運算符繼承interface

image

第二個不一樣——聯合定義類型不能被`interface`繼承

一樣,這個類的實現類似, interface是一個「靜態」圖紙——它不能實現兩個結構中的一個,因此它不能被聯合類型合併繼承。

3. 類型別名關鍵字不能聲明合併

interface有聲明合併,可是類型別名沒有。

什麼是聲明合併?

你能定義屢次相同的interface,這些定義將要合併爲一個。

image

聲明合併

這種方式對於類型別名就不成立,由於類型別名是獨一無二的實體(對於全局和模塊域)。

image

第三個不一樣——類型別名不支持聲明合併。

當咱們爲沒有使用Typescript創做的庫寫第三方環境定義的時候,經過interface的聲明合併是很是重要的,若是一些定義沒有的話,使用者能夠選擇性的擴展它。

若是咱們的庫是使用Typescript寫的,而且自動生成環境定義則一樣使用。

這是惟一的用例,你應該老是使用interface而不是類型別名。

我應該如何使用React的Props和State?

通常的,你要使用的一致就能夠(不管使用類型別名仍是interface),就我我的而言,我仍是推薦使用類型別名

  • 書寫起來更短type Props = {}
  • 你的用法是統一的(你不用爲了類型交叉而interface類型別名混用)
// BAD
interface Props extends OwnProps, InjectedProps, StoreProps {}
type OwnProps = {...}
type StoreProps = {...}
// GOOD
type Props = OwnProps & InjectedProps & StoreProps
type OwnProps = {...}
type StoreProps = {...}


複製代碼
  • 你組件公開的props/state不能被動態替換(譯者注:由於原文做者這裏說的 monkey patched翻譯爲動態替換 what-is-monkey-patching),就這個緣由,你組件的使用者就不能利用interface的聲明合併。對於擴展應該有像HOC這樣明確的模式。

總結

在這遍文章中咱們學到了在Typescript 2.7interface類型別名的不一樣。

有了這個,咱們得出在特定的場景中應該如何去定義編譯類型的結論。

讓咱們來回顧一下:

  • 類型別名 能像interface同樣,可是他們有三個重要的區別(聯合類型,聲明合併)
  • 使用適合你或者你團隊的東西,可是要保持一致
  • 當你寫個庫或者定義第三方環境類型的時候,在公開的API中老是使用interface
  • 在你的React組件的state/props中考慮使用類型別名
相關文章
相關標籤/搜索