Mapped Types是通过动态地转换(重命名、修改)另一个类型的所有属性而构建的类型。其语法基于in构造:
type Readonly<T> = { readonly [K in keyof T]: T[K]; } type User = { name: string; age: number; } const u: Readonly<User> = { name: 'Eve', age: 22 }; u.name = 'Bob'; // 错误:name为只读
细节:
-?或+?来修改修饰符(readonly、optional),移除或添加它们。包含所有修饰符的示例:
type PartialMutable<T> = { -readonly [K in keyof T]?: T[K]; };
"应用带有optional修饰符的mapped type,是否仅影响第一级属性,还是嵌套对象也会受影响?"
回答: 不,带有optional ?的mapped type仅影响第一级属性。嵌套对象需要单独转换,通常使用递归或额外的mapped types。
示例:
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
故事
在一个项目中,为了节省时间,使用了标准的Partial<T>来处理深层表单。然而,第二和第三层级的字段并未设置为可选,导致在缺少嵌套键时运行时出现意外错误。
故事
曾试图仅在子对象中删除readonly属性,结果仅对顶层应用了mapped type:
type Mutable<T> = { -readonly [K in keyof T]: T[K] }
结果,类型为{ readonly foo: { readonly bar: number } }的字段在嵌套中保持不变,导致团队困惑并增加了维护难度。
故事
在复杂的数据模型中,应用了嵌套的mapped types以合并多个工具类型(例如,Readonly & Partial)。由于组合顺序错误,产生了意外的类型兼容性冲突,导致编译器开始输出混乱的错误信息。