TypeScript中,interface和type使用上有什麼區別?

發表於2024-02-23

TypeScript 是 JavaScript 的一個超集,透過為 JavaScript 提供型別系統和其他語言特性來增強 JavaScript 的功能(配合VSCode,程式碼提示真的絲滑)。TypeScript 可以在編譯時進行型別檢查,從而提供更好的程式碼可讀性和可維護性,並且可以在開發過程中減少錯誤和除錯時間),減少了很多低階語法錯誤,這類問題有時候排查好久才會發現,查到的時候往往會忍不住罵娘。

我使用TypeScript的時長差不多兩年半了,在使用的初期,我便注意到在 TypeScript 中,interface 和 type 都可以用來定義物件的型別。

// 使用 interface 定義物件型別
interface User {
  name: string;
  age: number;
}

// 使用 type 定義物件型別
type User = {
  name: string;
  age: number;
}

上面定義的兩個User物件型別,效果是等效的,在宣告物件型別,函式的引數和返回型別等最常用的場景中使用起來效果沒有任何差別。

但是二者的使用方式其實還是有挺多區別,花幾分鐘瞭解之後,還是可以在小白麵前裝一下的。

哈哈,玩笑玩笑,最終還是為了更好地使用工具。

總結起來包括了6點,TypeScript的官方檔案中也有部分描述,點選末尾原文連結可以跳轉官方檔案(這裡提一句,TS的官方檔案寫得真好,強烈建議讀英文原版檔案,一開始可能有點慢,但是很快就適應過來了)。

1. interface 可以被類實現和擴充套件,而 type 不行

下面的例子中,用interface宣告瞭Animal,用type宣告瞭Animal2,當我試圖實現(implements)Animal2的時候,就報錯了。


interface Animal {
  name: string;
  eat(): void;
}

type Animal2 {
  name: string;
  eat(): void;
}

class Cat implements Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(`${this.name} is eating.`);
  }
}
// 錯啦,type定義的物件型別不能被實現
class Dog implements Animal2 {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(`${this.name} is eating.`);
  }
}

interface就是用來實現的,就像信任就是用來辜負的一樣。

2. 同名interface 可以被合併,而 type 不行。

在同一作用域內定義了兩個相同名稱的 interface,TypeScript 會將它們合併為一個。但是如果定義了兩個相同名稱的 type,則會產生命名衝突錯誤。


interface A {
  name: string;
}

interface A {
  age: number;
}

// A 介面被合併為 { name: string; age: number; }
const a: A = {
  name: 'Jack',
  age: 20
}

// Error: Duplicate identifier 'B'.
type B = {
  name: string;
}

type B = {
  age: number;
}

3. type可以用於宣告組合型別和交叉型別,interface則不行

下面這個case就是用type宣告瞭組合型別和交叉型別。

interface InterfaceA {
  key1: string;
}

interface InterfaceB {
  key2: number;
}

type UnionType = InterfaceA | InterfaceB;
type IntersectionType = InterfaceA & InterfaceB;

const obj1: UnionType = { key1: 'hello' }; // 符合 InterfaceA
const obj2: UnionType = { key2: 42 }; // 符合 InterfaceB
const obj: IntersectionType = { key1: 'hello', key2: 42 }; // 同時符合 InterfaceA 和 InterfaceB

4. type宣告的物件型別可以拿來組合成新的物件型別,interface不行

type Animal = {
  name: string
}

type Bear = Animal & { 
  honey: boolean 
}

const bear = getBear();
bear.name;
bear.honey;

5. 在定義物件型別時,interface 和 type 的語法略有不同。interface 使用花括號 {},而 type 使用等號 =。

這點有點湊數,但是確實是新手日常寫程式碼經常混淆的點

// interface 使用花括號 {} 定義物件型別
interface User {
  name: string;
  age: number;
}
// type 使用等號 = 定義物件型別
type User = {
  name: string;
  age: number;
}

6. type可以給基本型別起別名,interface不行


type StringTypeHAHAHHAHA = string;
// interface做不到

——分割線————————————————

列舉出來一看,差別還是挺多的,但是這些點其實沒有必要去記憶,因為TypeScript的工具鏈相當完善,不合適的用法編輯器都會有清晰的提示。

在實際應用中,除了功能性的剛性約束,更重要的是用型別去表達一個準確的語義,事實上許多複雜型別需要組合使用type和interface才能實現。

本文權當做了一個趣味探索,有其他關於TypeScript好玩的點,歡迎留言交流。

相關文章