一起聊聊 TypeScript 中的實用類型(utility type)和轉換類型
在學習 TypeScript 中遇到了Record 這個類型, 一開始不知道其用途, 查找了一下說明才得知:
Record<K extends keyof any, T> 是 TypeScript 提供的一個實用類型(utility type),用于構造一個對象類型,其中鍵 K 的集合可以是任意類型(通常是字符串、數字或符號),對應的值類型為 T。
1. 詳細解釋
1.1 定義
Record<K extends keyof any, T> 的定義如下:
type Record<K extends keyof any, T> = {
[P in K]: T;
};
- K extends keyof any:表示 K 可以是任何合法的鍵類型。keyof any 是 TypeScript 中的一個特殊類型,它等價于 string | number | symbol。
- T:表示屬性的值的類型。
- { [P in K]: T; }:這是一種映射類型語法,表示生成一個對象類型,這個對象的鍵是 K 中的每一個鍵,其對應的值類型都是 T。
1.2 用法示例
- 創建一個簡單的對象類型: 假設我們想要創建一個對象類型,鍵是字符串,值是數字:
type StringToNumberMap = Record<string, number>;
const example: StringToNumberMap = {
a: 1,
b: 2,
c: 3
};
- 限制鍵的集合: 假設我們有一組特定的鍵,值的類型是布爾型:
type Options = "option1" | "option2" | "option3";
type OptionFlags = Record<Options, boolean>;
const example: OptionFlags = {
option1: true,
option2: false,
option3: true
};
- 結合接口使用: 如果我們有一個接口Person,我們想要創建一個包含多個Person對象的記錄:
interface Person {
name: string;
age: number;
}
type PersonDictionary = Record<string, Person>;
const persons: PersonDictionary = {
john: { name: "John Doe", age: 25 },
jane: { name: "Jane Smith", age: 30 }
};
1.3 詳細示例
假設我們需要管理一組用戶,每個用戶都有一個唯一的標識符(ID)。我們可以使用 Record 來定義一個用戶字典:
interface User {
id: number;
name: string;
email: string;
}
type UserDictionary = Record<number, User>;
const users: UserDictionary = {
1: { id: 1, name: "John Doe", email: "john.doe@example.com" },
2: { id: 2, name: "Jane Smith", email: "jane.smith@example.com" },
3: { id: 3, name: "Emily Johnson", email: "emily.johnson@example.com" }
};
// 訪問用戶信息
console.log(users[1].name); // 輸出: John Doe
在這個示例中:
- User 接口定義了用戶對象的結構。
- UserDictionary 使用 Record<number, User> 創建了一個類型,該類型的鍵是數字,值是 User 類型。
- users 變量是一個 UserDictionary 類型的對象,包含多個用戶條目。
2. 類型工具
Record<K extends keyof any, T> 類型在 TypeScript 中非常有用,可以用來定義一個鍵和值類型的映射。它允許我們動態地創建具有特定鍵集合和值類型的對象類型,廣泛應用于需要鍵值對數據結構的場景。
在 TypeScript 中還有不少類似的類型工具用于操作和轉換類型。以下是它們的具體區別和用途:
- Partial
作用:將類型 T 的所有屬性變為可選。
用法:
interface Person {
name: string;
age: number;
}
type PartialPerson = Partial<Person>;
// Equivalent to: { name?: string; age?: number; }
- Required
作用:將類型 T 的所有屬性變為必需。
用法:
interface Person {
name?: string;
age?: number;
}
type RequiredPerson = Required<Person>;
// Equivalent to: { name: string; age: number; }
- Readonly
作用:將類型 T 的所有屬性變為只讀。
用法:
interface Person {
name: string;
age: number;
}
type ReadonlyPerson = Readonly<Person>;
// Equivalent to: { readonly name: string; readonly age: number; }
- Pick<T, K extends keyof T>
作用:從類型 T 中挑選一組屬性 K 組成新的類型。
用法:
interface Person {
name: string;
age: number;
address: string;
}
type PersonNameAndAge = Pick<Person, 'name' | 'age'>;
// Equivalent to: { name: string; age: number; }
- Record<K extends keyof any, T>
作用:構建一個類型,其鍵為 K 類型,值為 T 類型。
用法:
type PersonRecord = Record<string, number>;
// Equivalent to: { [key: string]: number; }
- Exclude<T, U>
作用:從類型 T 中排除可以賦值給 U 的類型。
用法:
type T = string | number | boolean;
type Excluded = Exclude<T, boolean>;
// Equivalent to: string | number
- Extract<T, U>
作用:從類型 T 中提取可以賦值給 U 的類型。
用法:
type T = string | number | boolean;
type Extracted = Extract<T, boolean>;
// Equivalent to: boolean
- Omit<T, K extends keyof any>
作用:構建一個類型,其具有類型 T 的屬性,除了那些在 K 中的屬性。
用法:
interface Person {
name: string;
age: number;
address: string;
}
type PersonWithoutAddress = Omit<Person, 'address'>;
// Equivalent to: { name: string; age: number; }
- NonNullable
作用:從類型 T 中排除 null 和 undefined。
用法:
type T = string | number | null | undefined;
type NonNullableT = NonNullable<T>;
// Equivalent to: string | number
- Parameters<T extends (...args: any) => any>
作用:獲取函數類型 T 的參數類型組成的元組。
用法:
type Func = (a: string, b: number) => void;
type Params = Parameters<Func>;
// Equivalent to: [string, number]
這些類型工具在類型操作和變換中非常有用,幫助開發者更靈活地處理和定義類型。