TypeScript: type alias 與 interface


官方文檔中有關於兩者對比的信息,隱藏在 TypeScript Handbook 中,見 Interfaces vs. Type Aliases 部分。

但因為這一部分很久沒更新了,所以其中描述的內容不一定全對。

比如,

區別點之一:Type Alias 不會創建新的類型,體現在錯誤信息上。

One difference is, that interfaces create a new name that is used everywhere. Type aliases don’t create a new name — for instance, error messages won’t use the alias name.

不完全正確。直接通過 type 定義的初始類型,是會創建相應的類型名稱的。

什么意思呢。就是說,不是使用 &, | 等操作符創建的 union type 及 intersection type。

type Person = {
  name: string;
  age: number;
};

// [x] Property 'age' is missing in type '{ name: string; }' but required in type 'Person'.ts(2741)
const bob: Person = {
name: "bob"
};

注意這里錯誤信息使用的是類型 Person 而不是對應的 plain object 對象。

區別點之二:type alias 不能被 extendsimplements

實際上在擴展和實現上二者已經沒有區別,甚至可以混用,比如讓一個 class 同時實現 interface 和 type alias 定義的類型。

type PointType = {
  x: number;
  y: number;
};

interface PointInterface {
a: number;
b: number;
}

class Shape implements PointType, PointInterface {
constructor(public a = 1, public b = 2, public x = 3, public y = 4) {}
}

區別點之三:type alias 不能擴展和實現其他類型

不完全正確。因為通過正交操作符(intersection type) & 可以達到 extends 的目的。

interface Person {
  name: string;
}

interface Job {
title: string;
}

type EmployeeType = Person & Job;

class Employee implements EmployeeType {
constructor(public name = "Nobody", public title = "Noone") {}
}

上面可以看到,兩者大部分情況下不用過多區分。

在使用了 union type 的時候,一些區別才開始顯現。其實也算不得區別,因為只有 type alias 可通過 union type 定義。

當 type 包含 union type 時,該類型是不能被實現和擴展的。

interface Triangle {
  area: number;
}

interface Square {
width: number;
height: number;
}

type ShapeType = Triangle | Square;

// [x] An interface can only extend an object type or intersection of object types with statically known members.ts(2312)
interface MyShape extends ShapeType;

class Shape implements ShapeType{
// [x] A class can only implement an object type or intersection of object types with statically known members.ts(2422)
}

因為 union type 描述的是一個或者的狀態,一個類不可能即是此類型也是另外種類型。interface 也不可能繼承一個類型還不確定的類型。

類型合並

最明顯的一點區別,是在進行類型合並(Declaration Merging)的時候,type alias 是不會被合並的,而同名的多個 interface 會合並成一個。

interface Person {
  name: string;
}
interface Person {
  age: number;
}

const person: Person = {
name: "Bob",
age: 9
};

對於 type alias,存在同名時直接報錯。

type Person {  // [x] Duplicate identifier 'Person'.ts(2300)
  name: string;
}
type Person { // [x] Duplicate identifier 'Person'.ts(2300)
  age: number;
}

明白這點對於三方庫的作者來說很重要。假如你寫了個 npm 包,導出的是 type,則使用者無法通過簡單定義同名類型來進行擴充。

所以,寫庫的時候,盡量使用 interface。

結論

官方推薦用 interface,其他無法滿足需求的情況下用 type alias。

但其實,因為 union type 和 intersection type 是很常用的,所以避免不了大量使用 type alias 的場景,一些復雜類型也需要通過組裝后形成 type alias 來使用。所以,如果想保持代碼統一,可盡量選擇使用 type alias。通過上面的對比,type alias 其實可函蓋 interface 的大部分場景。

對於 React 組件中 props 及 state,使用 type alias,這樣能夠保證使用組件的地方不能隨意在上面添加屬性。如果有自定義需求,可通過 HOC (Higher-Order Components)二次封裝。

編寫三方庫時使用 interface,其更加靈活自動的類型合並可應對未知的復雜使用場景。

相關資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM