介紹
映射類型允許您透過迭代其鍵來轉換現有物件類型。將它們視為 Array.prototype.map() 但處於 類型層級。語法 { [K in keyof T]: T[K] } 透過對 T 的每個屬性套用轉換來建立新類型。這就是 TypeScript 的許多內建實用程式類型在幕後工作的方式。
基本映射類型
最簡單的映射類型會建立現有類型的克隆:
type Clone<T> = { [K in keyof T]: T[K] };
interface User {
name: string;
age: number;
}
type UserClone = Clone<User>;
// { name: string; age: number }
新增修飾符
映射類型可以套用三個修飾符:readonly、?(可選)和 -(刪除):
// Make all properties readonly
type MyReadonly<T> = { readonly [K in keyof T]: T[K] };
// Make all properties optional
type MyPartial<T> = { [K in keyof T]?: T[K] };
// Remove readonly (the - modifier)
type MyMutable<T> = { -readonly [K in keyof T]: T[K] };
// Remove optional
type MyRequired<T> = { [K in keyof T]-?: T[K] };
這些正是內建 Readonly<T>、Partial<T> 和 Required<T> 的實作方式。
使用 as 鍵重新映射進行過濾
TypeScript 4.1 引進了使用 as 子句的鍵重新映射。這允許過濾或重命名鍵:
// Filter keys that are strings
type StringKeys<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
interface User {
name: string;
age: number;
email: string;
}
type OnlyStrings = StringKeys<User>;
// { name: string; email: string }
模板文字關鍵更改
將映射類型與 模板文字類型 結合起來以轉換鍵名稱:
// Add a prefix to all keys
type WithPrefix<T, P extends string> = {
[K in keyof T as `${P}_${K & string}`]: T[K];
};
interface User {
name: string;
age: number;
}
type Prefixed = WithPrefix<User, 'user'>;
// { user_name: string; user_age: number }
轉換為 getter/setter 約定:
type Getters<T> = {
[K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
};
type UserGetters = Getters<{ name: string; age: number }>;
// { getName: () => string; getAge: () => number }
選擇和省略實施
以下是 Pick 和 Omit 的內部運作原理:
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
type MyOmit<T, K extends keyof any> = {
[P in keyof T as P extends K ? never : P]: T[P];
};
interface User {
name: string;
age: number;
email: string;
}
type NameOnly = MyPick<User, 'name'>;
// { name: string }
type NoEmail = MyOmit<User, 'email'>;
// { name: string; age: number }
實用圖案
Deep Partial(遞歸映射類型)
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
可空屬性
type Nullable<T> = {
[K in keyof T]: T[K] | null;
};
使用映射重命名鍵
type RenameKeys<T, M extends Record<string, string>> = {
[K in keyof T as K extends keyof M ? M[K] : K]: T[K];
};
結論
映射類型是 TypeScript 類型轉換功能的支柱。從基本修飾符(readonly、?)到使用模板文字的高級鍵重新映射,它們使您可以對類型如何演變進行細粒度控制。與條件類型結合,它們實現了編譯時元編程,使 TypeScript 真正強大。

