理解同态映射类型如何保留修饰符,以及 as 子句如何重命名或过滤键。
在 Kodokon 中打开本课映射类型遍历一组键来产生一个新的对象类型。[K in keyof T] 这种形式被称为同态的:编译器知道结构来自 T,并会自动复制每个原始属性的 readonly 和 ? 修饰符。+ 和 - 前缀让你能够显式地添加或移除这些修饰符:这正是 Partial、Required 和 Readonly 背后的内部机制。
type Mutable<T> = {
-readonly [K in keyof T]-?: T[K];
};
interface Config {
readonly host?: string;
readonly port?: number;
}
type Draft = Mutable<Config>;
// { host: string; port: number }自 TypeScript 4.1 起,as 子句支持键重映射:每个键都可以即时重命名,通常通过模板字面量类型来完成。而如果该子句产生 never,这个键就会直接从结果中被移除:这就是官方的属性过滤机制。注意示例中的 & string:keyof T 可能包含 symbol 或 number 类型的键,它们与模板字面量不兼容。
type Getters<T> = {
[K in keyof T & string as `get${Capitalize<K>}`]:
() => T[K];
};
interface User { name: string; age: number }
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }
type OnlyMethods<T> = {
[K in keyof T as
T[K] extends (...args: never[]) => unknown
? K : never]: T[K];
};一个常被忽视的规范细节:当应用于数组或元组时,同态映射类型不会产生一个带有 0、1 和 length 键的对象。编译器会保留类型的本质:它变换元素,并保留数组或元组的形状。这就是 Readonly<[number, string]> 能保持为元组的原因。一旦映射类型不再是同态的,例如使用 [P in K](其中 K 是任意的键联合类型),这种保留就会消失。
type Immutable<T> = {
readonly [K in keyof T]: T[K];
};
type Pair = Immutable<[number, string]>;
// readonly [number, string]: the tuple survives
type List = Immutable<string[]>;
// readonly string[]as 子句对某个键产生 never 时会发生什么?[number, string] 时,{ readonly [K in keyof T]: T[K] } 产生什么?-? 修饰符的作用是什么?