1. 程式人生 > 其它 >TypeScript 裡 interface 和 type 的區別

TypeScript 裡 interface 和 type 的區別

interface X {
    a: number
    b: string
}

type X = {
    a: number
    b: string
};

我們可以用 interface 去 extend type:

用 class 實現 type:

用 class 實現 type 和 interface 的混合:

type intersection 的用法,使用 & 連線多個 type:

使用 partial 將部分 type 的欄位變成 optional:

Hybrid Types with both type alias and interface

您可能偶爾想要定義一個物件,它既充當函式又充當物件,並具有附加屬性。

我們在這裡談論的是為函式(可呼叫物件)和該函式的靜態屬性定義型別。

看個例子:

interface Counter {
    // callable part
    (start: number): string
    // static properties
    interval: number
    reset(): void
  }
  
  const getCounter = () => {
     const counter = ((start:number) => {}) as Counter
     counter.interval = 123
     counter.reset = () => {}
     return counter
  }
  
  const callable = getCounter();
  callable(10);
  callable.reset();
  callable.interval = 5;

用 interface 定義了一個 Counter, 該型別兼有 callable 和靜態屬性兩種特徵。

最佳實踐:還是分開定義吧。

callable 的定義:

靜態屬性的定義:

最後的 counter 型別:

型別與型別之間連線用 &,介面的組合用 extends.

In TypeScript, we have a lot of basic types, such as string, boolean, and number. These are the basic types of TypeScript. You can check the list of all the basic types here. Also, in TypeScript, we have advanced types and in these advanced types, we have something called type aliases. With type aliases, we can create a new name for a type but we don’t define a new type.

所以我們使用的 type 關鍵字,定義的只是類型別名,而不是全新的型別。

We use the type keyword to create a new type alias, that’s why some people might get confused and think that it’s creating a new type when they’re only creating a new name for a type. So, when you hear someone talking about the differences between types and interfaces, like in this article, you can assume that this person is talking about type aliases vs interfaces.

區別

在最新版本的 TypeScript 裡,二者的區別越來越小。

  • Interfaces are basically a way to describe data shapes, for example, an object.

  • Type is a definition of a type of data, for example, a union, primitive, intersection, tuple, or any other type.

interface 支援 declaration merging,而 type alias 不支援。

interface Song {
  artistName: string;
};

interface Song {
  songName: string;
};

const song: Song = {
  artistName: "Freddie",
  songName: "The Chain"
};

TypeScript will automatically merge both interfaces declarations into one, so when we use this Song interface, we’ll have both properties.

而 type alias 不支援,會遇到編譯錯誤:

Extends and implements

In TypeScript, we can easily extend and implement interfaces. This is not possible with types though.

Interfaces in TypeScript can extend classes, this is a very awesome concept that helps a lot in a more object-oriented way of programming. We can also create classes implementing interfaces.

例子:

class Car {
  printCar = () => {
    console.log("this is my car")
  }
};

interface NewCar extends Car {
  name: string;
};

class NewestCar implements NewCar {
  name: "Car";
  constructor(engine:string) {
    this.name = engine
  }
  printCar = () => {
    console.log("this is my car")
  }
};

這裡介面擴充套件了原始類,一個新的類又實現了介面。

元祖 Tuples

元組是 TypeScript 中一個非常有用的概念,它為我們帶來了這種新的資料型別,它包括兩組不同資料型別的值。

無法用 interface 定義元祖,但 interface 內部屬性可以用元祖作為資料型別。

interface Response {
  value: [string, number]
}

什麼時候用 interface,什麼時候用 type alias?

當您需要定義新物件或物件的方法時,介面會更好。 例如,在 React 應用程式中,當您需要定義特定元件將要接收的 props 時,最好使用介面而不是型別:

interface TodoProps {
  name: string;
  isCompleted: boolean
};

const Todo: React.FC<TodoProps> = ({ name, isCompleted }) => {
  ...
};

例如,當您需要建立函式時,型別會更好。 假設我們有一個函式將返回一個被呼叫的物件,這種方法更推薦使用類型別名:

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

type ReturnPerson = (
  person: Person
) => Person;

const returnPerson: ReturnPerson = (person) => {
  return person;
};

介面與物件和方法物件更好地工作,型別更好地與函式、複雜型別等一起工作。

更多Jerry的原創文章,盡在:"汪子熙":