對映型別

當你不想重複自己時,有時需要基於另一個型別來定義一個型別。

對映型別基於索引簽名的語法,索引簽名用於宣告未預先宣告的屬性型別。

ts
type OnlyBoolsAndHorses = {
[key: string]: boolean | Horse;
};
 
const conforms: OnlyBoolsAndHorses = {
del: true,
rodney: false,
};
Try

對映型別是一種泛型,它使用 PropertyKey 的聯合型別(通常透過 keyof 建立)來迭代鍵,從而建立一個新型別。

ts
type OptionsFlags<Type> = {
[Property in keyof Type]: boolean;
};
Try

在此示例中,OptionsFlags 將獲取型別 Type 中的所有屬性,並將它們的值更改為布林值。

ts
type Features = {
darkMode: () => void;
newUserProfile: () => void;
};
 
type FeatureOptions = OptionsFlags<Features>;
type FeatureOptions = { darkMode: boolean; newUserProfile: boolean; }
Try

對映修飾符

在對映過程中可以使用兩個額外的修飾符:readonly?,它們分別影響可變性和可選性。

你可以透過新增 -+ 字首來移除或新增這些修飾符。如果你不加字首,則預設為 +

ts
// Removes 'readonly' attributes from a type's properties
type CreateMutable<Type> = {
-readonly [Property in keyof Type]: Type[Property];
};
 
type LockedAccount = {
readonly id: string;
readonly name: string;
};
 
type UnlockedAccount = CreateMutable<LockedAccount>;
type UnlockedAccount = { id: string; name: string; }
Try
ts
// Removes 'optional' attributes from a type's properties
type Concrete<Type> = {
[Property in keyof Type]-?: Type[Property];
};
 
type MaybeUser = {
id: string;
name?: string;
age?: number;
};
 
type User = Concrete<MaybeUser>;
type User = { id: string; name: string; age: number; }
Try

透過 as 進行鍵重對映

從 TypeScript 4.1 開始,你可以在對映型別中使用 as 子句來重對映鍵。

ts
type MappedTypeWithNewProperties<Type> = {
[Properties in keyof Type as NewKeyType]: Type[Properties]
}

你可以利用模板字串型別等功能,透過先前的屬性名來建立新的屬性名。

ts
type Getters<Type> = {
[Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};
 
interface Person {
name: string;
age: number;
location: string;
}
 
type LazyPerson = Getters<Person>;
type LazyPerson = { getName: () => string; getAge: () => number; getLocation: () => string; }
Try

你可以透過條件型別產生 never 來過濾掉某些鍵。

ts
// Remove the 'kind' property
type RemoveKindField<Type> = {
[Property in keyof Type as Exclude<Property, "kind">]: Type[Property]
};
 
interface Circle {
kind: "circle";
radius: number;
}
 
type KindlessCircle = RemoveKindField<Circle>;
type KindlessCircle = { radius: number; }
Try

你可以對映任意聯合型別,不僅限於 string | number | symbol 的聯合,可以是任何型別的聯合。

ts
type EventConfig<Events extends { kind: string }> = {
[E in Events as E["kind"]]: (event: E) => void;
}
 
type SquareEvent = { kind: "square", x: number, y: number };
type CircleEvent = { kind: "circle", radius: number };
 
type Config = EventConfig<SquareEvent | CircleEvent>
type Config = { square: (event: SquareEvent) => void; circle: (event: CircleEvent) => void; }
Try

進一步探索

對映型別與本型別操作章節中的其他特性結合得很好,例如,這裡有一個使用了條件型別的對映型別,它根據物件是否將 pii 屬性設定為字面量 true,返回 truefalse

ts
type ExtractPII<Type> = {
[Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;
};
 
type DBFields = {
id: { format: "incrementing" };
name: { type: string; pii: true };
};
 
type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>;
type ObjectsNeedingGDPRDeletion = { id: false; name: true; }
Try

TypeScript 文件是一個開源專案。透過傳送 Pull Request 幫助我們改進這些頁面 ❤

此頁面的貢獻者
OTOrta Therox (7)
SFSergey Falinsky (2)
LLuke (1)
Wwebstrand (1)
SGHSteven G. Harms (1)
5+

最後更新:2026 年 3 月 27 日