網站搜尋

angular - Typescript 中介面與類別的差異


TypeScript 的介面(Interfaces)和類別(Classes)有什麼不同?我什麼時候應該使用類別?我什麼時候應該使用介面?它們各自的優點是什麼?

我需要為我的後端伺服器創建某種類型的 HTTP 請求(使用 Angular 2 來做),例如:

"fields": {
  "project": {
      "id": "10000"
  },
  "summary": "something's wrong",
  "issuetype": {
      "id": "10000"
  },
  "assignee": {             // not neccesary required
      "name": "homer"
  },
  "reporter": {
      "name": "smithers"
  },
  "priority": {            // not neccesary required
      "id": "20000"
  }
}

我應該用什麼來建造這些模型?謝謝!

答案#1

2019:差異與用法更新

首先,有一個明顯的差異:語法。這是一個簡單但必要理解的差別:介面屬性可以以逗號或分號結尾,而類別屬性只能以分號結尾。接下來是有趣的部分。關於何時使用與何時不使用的部分可能具有主觀性——這些是我給我團隊的人提供的指引,但其他團隊也可能因合理的原因有不同的指引。如果你的團隊做法不同,歡迎留言,我很想了解原因。

介面:允許在設計和編譯階段定義將被使用的型別,以實現強型別。它們可以被「實作」或「擴充」,但不能實例化(你不能 new 它們)。在轉譯為 JS 時會被移除,因此不佔用空間,但它們在執行時也無法進行型別檢查,所以你無法在執行時檢查變數是否實作了特定型別(例如 foo instanceof bar),只能透過檢查其擁有的屬性:使用 Typescript 進行介面型別檢查。

何時使用介面:當您需要為一個在程式中多個地方使用的物件建立屬性和函數的契約時使用它們,尤其是在多個檔案或函數中使用時。同時,當您希望其他物件以這組基礎屬性開始時也使用它們,例如擁有一個 Vehicle 介面,讓多個類別以特定的車輛類型來實作,如 Car、Truck、Boat(例如 class Car implements Vehicle)。

什麼時候不應使用介面:當你想要有預設值、實作、建構函式或函數(不只是簽名)時。

類別:也允許定義一種類型,可在設計和編譯時用於強型別,此外,也可以在運行時使用。這也意味著程式碼不會被編譯掉,因此會佔用空間。這是 @Sakuto 提到的一個關鍵差異,但其影響不僅僅是空間。這意味著類別可以進行類型檢查,即使在轉譯後的 JS 代碼中,也能保留對「它們是誰」的理解。進一步的差異包括:類別可以使用 new 來實例化,也可以被擴展,但不能被實現。類別可以有建構函數和實際的函數程式碼,以及預設值。

何時使用類別:當你想要創建具有實際功能程式碼的物件,並且有建構函式進行初始化,和/或你想要使用 new 創建它們的實例時,也可以使用類別來為簡單的資料物件設定預設值。另一個你可能想要使用類別的情況是進行型別檢查,但如果需要,也有介面(interface)的替代方法(參見介面章節 OS 連結)。

何時不使用類別:當你只有一個簡單的資料接口、不需要實例化它、希望它被其他物件實現、或者希望只是簡單地將接口放在現有物件上(想想型別定義檔案),或是類別會佔用過多空間或不必要時,都不應使用類別。順帶一提,如果你查看 .d.ts 檔案,你會注意到它們只使用接口和型別,因此在轉譯成 JavaScript 時這些會完全被移除。

最後說明,除了類別和介面之外,還有兩個其他選項,第一個是所謂的「類型 (type)」,它與介面相當相似,但請參考這篇 SO 文章,特別是 2019 更新的答案:TypeScript 中的介面 vs 類型。最後一個選項是以函數式程式設計風格 (而非物件導向) 來使用 TS。

要閱讀完整的故事和範例,請訪問 PassionForDev.com;想要查看更多關於類別與繼承的文章以及範例,請訪問 https://jameshenry.blog/typescript-classes-vs-interfaces/。

答案#2

根據 Angular 2 的風格指南,建議在類型定義中使用 Class 而非 Interface。主要的區別在於,class 在編譯後仍會保留,而 Interface 則會完全被移除,因為它們沒有任何用途。

只要整個專案保持一致,並且偏好有品味的風格指南,說不定有一天你會需要在模型中加入方法。

查看以下答案以獲取更多詳情:https://stackoverflow.com/a/55505227/5463904

答案#3

簡單來說,Class 用於創建物件,而 Interface 幫助你了解這些物件應該包含什麼。

類別就像一個藍圖/模板,我們可以用它來創建物件。介面就像一份契約,類別必須同意去實現該介面,或者定義這個藍圖應該包含什麼內容。

一個簡單的類別:

class Car {
    engine: string; // 'var' is not used;

    constructor(engine: string) { // This is how we create constructor
        this.engine = engine;
    }

    display(): void { // 'function' keyword is not used here.
        console.log(`Engine is ${this.engine}`); // just a log.
    }
}

var objCar = new Car('V8'); // creates new onject
objCar.display(); // output: Engine is V8
console.log(objCar.engine); // output: V8 (accessing member here)

一個簡單的介面:

    interface IPerson { // This is how we create an interface.
        firstName: string, // use commas to separate.
        lastName: string, // In classes we use semi-colon to separate.
        displayDetails: (number) => string
    }

    // We are going to store 'interface object' in a variable.
    // i.e. we are implementing interface with variable(not class!!)
    var customer: IPerson = {

        firstName: 'jose jithin', // 'implements' variables
        lastName: 'stanly',

        // Now method implementation.
        // Note: the syntax of 'displayDetails' maybe a bit confusing (given below)
        // as two colons are used.
        // It specifies a return type(string) here for this method. 
        displayDetails: (rank): string => { return `This person has rank ${rank}. ` }  

        // It can be rewritten as following too.
        displayDetails: (rank) => { return `This person has rank ${rank}. ` };
        // i.e. return type need not be specified, just like a normal method definition syntax.
    }

    console.log(customer.firstName); // output: jose jithin

    console.log(customer.lastName);  // output: stanly

    console.log(customer.displayDetails(1)); // output: This person has rank 

我已在文章中詳細介紹了類別和介面。這可能有助於你理解。