Skip to content
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

映射类型

当你不想重复自己时,有时一个类型需要基于另一个类型。

映射类型建立在索引签名的语法之上,索引签名用于声明未提前声明的属性的类型:

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
>;
Try

映射修饰符

在映射过程中可以应用两个额外的修饰符:readonly?,它们分别影响可变性和可选性。

你可以通过添加 -+ 前缀来移除或添加这些修饰符。如果不添加前缀,则假定为 +

ts
// 从类型的属性中移除 'readonly' 属性
type 
CreateMutable
<
Type
> = {
-readonly [
Property
in keyof
Type
]:
Type
[
Property
];
}; type
LockedAccount
= {
readonly
id
: string;
readonly
name
: string;
}; type
UnlockedAccount
=
CreateMutable
<
LockedAccount
>;
Try
ts
// 从类型的属性中移除 'optional' 属性
type 
Concrete
<
Type
> = {
[
Property
in keyof
Type
]-?:
Type
[
Property
];
}; type
MaybeUser
= {
id
: string;
name
?: string;
age
?: number;
}; type
User
=
Concrete
<
MaybeUser
>;
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>;
Try

你可以通过条件类型产生 never 来过滤掉键:

ts
// 移除 'kind' 属性
type 
RemoveKindField
<
Type
> = {
[
Property
in keyof
Type
as
Exclude
<
Property
, "kind">]:
Type
[
Property
]
}; interface Circle {
kind
: "circle";
radius
: number;
} type
KindlessCircle
=
RemoveKindField
<Circle>;
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
>
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
>;
Try