跳至主要内容

[TS] Unions and Intersection Types

在 TypeScript 中:

  • 先留意 Unions 和 Intersection 使用在 primitive type 和 object 的表現會「感覺」不太一樣
  • 聯集(Unions):能夠符合其中一種型別即可
  • 交集(Intersection)則是要能夠同時符合兩種型別
    • primitive type 通常用 & 會變成 never,因為不可能同時滿足兩個 primitive type
    • object 的話,該物件需要同時有 A type 中的屬性和 B type 中的屬性(少一個都不行)
/** 對於 primitive type 來說 */
type UnionPrimitive = string | number; // string | number
type IntersectionPrimitive = string & number; // never

/** 對於 object type 來說 */
type Circle = {
color: string;
radius: number;
};

type Rectangle = {
color: string;
width: number;
height: number;
};

// 只需符合 Circle 的屬性或 Rectangle 的屬性即可
const foo: Circle | Rectangle = {
color: 'red',
radius: 15,
height: 20,
};

// 需要同時帶有 Circle 和 Rectangle 中的屬性(缺一不可)
const bar: Circle & Rectangle = {
color: 'red',
radius: 15,
width: 30,
height: 20,
};

Union Types

使用 Union 來定義伺服器回應的狀態

這樣就不需要使用 code?: numberresponse?: {...} 這樣的寫法,可以明確知道不同的通訊狀態下需要必備的欄位有哪些:

// https://www.staging-typescript.org/docs/handbook/unions-and-intersections.html#discriminating-unions
type NetworkLoadingState = {
state: 'loading';
};

type NetworkFailedState = {
state: 'failed';
code: number;
};

type NetworkSuccessState = {
state: 'success';
response: {
title: string;
duration: number;
summary: string;
};
};

// Create a type which represents only one of the above types
// but you aren't sure which it is yet.
type NetworkState = NetworkLoadingState | NetworkFailedState | NetworkSuccessState;

Intersection Types

使用 Intersection Types 為每一個 response 加上 Error Handling:

interface ErrorHandling {
success: boolean;
error?: { message: string };
}

interface ArtworksData {
artworks: { title: string }[];
}

interface ArtistsData {
artists: { name: string }[];
}

type ArtworksResponse = ArtworksData & ErrorHandling;
type ArtistsResponse = ArtistsData & ErrorHandling;