Skip to content

TypeScript 型別宣告技巧

當專案變大時,資料間的關係會變複雜,宣告型別的方式就會變得很重要,以下是一些型別宣告的技巧:

1. PartialPickOmit

Partial 將型別的屬性變為可選的
Pick 從型別中選擇某些屬性
Omit 從型別中排除某些屬性

typescript
interface User {
    id: number;
    name: string;
    email: string;
}
// 將 User 型別的所有屬性變為可選的,Partial 是 TypeScript 2.1 新增的工具型別,用來將一個型別的所有屬性變為可選的。
type PartialUser = Partial<User>;
// 從 User 型別中選擇 name 和 email 屬性,Pick 是 TypeScript 2.1 新增的工具型別,用來從一個型別中選擇某些屬性。
type UserNameAndEmail = Pick<User, 'name' | 'email'>;
// 從 User 型別中排除 email 屬性,Omit 是 TypeScript 4.1 新增的工具型別,用來從一個型別中排除某些屬性。
type UserWithoutEmail = Omit<User, 'email'>;

2. Extract

從聯合型別中提取特定型別

typescript
type UserInput = string | number | Date | string[];
type TextualInput = Extract<UserInput, string | string[]>;

function handleText(input: TextualInput) {
    console.log(`Handling text: ${input}`);
}

// 正確的用法
// 不會有 TypeScript 類型錯誤
handleText("Hello, world!");
handleText(["Hello", "world!"]);

// 錯誤的用法
handleText(42); // TypeScript 類型錯誤
handleText(new Date()); // TypeScript 類型錯誤

3. Exclude

從聯合型別中排除某些型別

typescript
type UserInput = string | number | Date | string[];
type NonTextualInput = Exclude<UserInput, string | string[]>;

function handleNonText(input: NonTextualInput) {
    console.log(`Handling non-textual input: ${input}`);
}

4. readonly

使屬性不可變

typescript
interface User {
    readonly id: number;
    name: string;
    email: string;
}

5. Record

將一個物件的key、value轉為一個型別的

typescript
type User = {
    id: number;
    name: string;
    email: string;
};
type UserRecord = Record<string, User>;
const users: UserRecord = {
    "1": { id: 1, name: "John", email: "[email protected]" },
    "2": { id: 2, name: "Jane", email: "[email protected]" },
};

6. Creating types from values in array

限制一個變數的值必須在陣列中
https://github.com/microsoft/TypeScript/issues/28046

typescript
const animals = ['cat', 'dog', 'mouse'] as const
type Animal = typeof animals[number]

// type Animal = 'cat' | 'dog' | 'mouse'