实战指南:基于 The Concise TypeScript Book 的深度解析)
文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载映射类型Mapped Types是 TypeScript 类型系统中以类型生成类型的核心能力之一它允许你在编译期遍历现有类型的每一个属性并通过映射函数将其转换为全新的类型结构。本文以《The Concise TypeScript Book》开源仓库中 西班牙语版映射类型章节 为主线结合仓库内 映射类型修饰符、索引签名、模板联合类型 与 类型操作总览 等章节带你从零掌握映射类型的语法、修饰符、键重映射与内置工具类型的底层实现并能在实际项目中用它写出可复用的类型工具。什么是映射类型从已有类型推导新类型在 TypeScript 中类型系统不是静态封闭的——你可以基于一个已有的类型通过变换其每个属性来构造出全新的类型。这就是映射类型的核心思想访问现有类型的属性集合再逐一对属性进行变换最终产生一个表达相同信息、但结构不同的新类型。访问属性集合的关键运算符是keyof它返回一个对象类型所有属性名的联合类型。例如type MyType { foo: string; bar: number; }; // keyof MyType 等价于 foo | bar有了属性名的联合类型就可以用[P in keyof T]的语法逐一遍历每个属性形成映射。仓库中 映射类型章节 给出的权威示例如下type MyMappedTypeT { [P in keyof T]: T[P][]; }; type MyType { foo: string; bar: number; }; type MyNewType MyMappedTypeMyType; const x: MyNewType { foo: [hello, world], bar: [1, 2, 3], };我们来逐步拆解这段代码的执行过程keyof T得到MyType的属性名联合foo | barP in keyof T表示遍历P每次取一个属性名T[P][]是索引访问类型Indexed Access Type与数组后缀的组合表示取属性P的类型T[P]再包一层数组于是MyNewType展开后等价于{ foo: string[]; bar: number[] }。MyNewType与MyType承载的信息量一致同样的两个字段但每个字段的值形态从string/number变成了string[]/number[]。这正是映射类型的价值同一份数据用不同的类型形态去表达且变换过程完全由编译器推导无需手写重复的接口定义。支撑映射类型的三个基石keyof、索引访问与索引签名keyof 运算符keyof是映射类型的入口它把对象的属性名提炼成字面量联合类型。没有keyof就无法遍历属性。它是连接对象类型与属性名字符串集合的桥梁也是后续所有映射、修饰符、键重映射操作的前提。索引访问类型 Type[Key]T[P]的写法即索引访问类型Indexed Access Types在 类型操作章节 中有专门讲解type Person { name: string; age: number; }; type AgeType Person[age]; // number它同样支持对元组按索引取值type MyTuple [string, number, boolean]; type MyType MyTuple[2]; // boolean映射类型中的T[P]正是这一特性的泛化应用——P不是固定的字面量而是遍历中的变量。索引签名string / number / symbol当被映射的类型带有索引签名时映射规则会作用于索引签名字段上。索引签名章节 说明 TypeScript 支持string、number、symbol三类索引type K { [name: string | number]: string; }; const k: K { x: x, 1: b }; console.log(k[x]); console.log(k[1]); console.log(k[1]); // Same result as k[1]注意一个 JavaScript 层面的行为数字索引会被自动转换为字符串索引因此k[1]与k[1]返回的是同一个值。理解这一点有助于理解为什么映射到带数字索引的类型时键的联合类型中数字与字符串字面量可能表现出一致性。映射类型修饰符readonly、-readonly 与可选 ?映射类型不仅能把属性值换成别的类型还能变换属性本身的修饰状态。仓库的 映射类型修饰符章节 给出了三个修饰符修饰符含义readonly或readonly将映射结果中的属性标记为只读-readonly将映射结果中的属性还原为可写可变?将映射结果中的属性标记为可选对应示例type ReadOnlyT { readonly [P in keyof T]: T[P] }; // 所有属性变为只读 type MutableT { -readonly [P in keyof T]: T[P] }; // 所有属性变为可写 type MyPartialT { [P in keyof T]?: T[P] }; // 所有属性变为可选前缀是可省略的默认写法因此readonly [P in keyof T]与readonly [P in keyof T]等价而-readonly的作用恰好相反用于解除只读。关于只读的含义只读属性章节 有一个重要提醒readonly阻止的是重新写入属性这一操作它并不提供整体不可变的保证——深层嵌套对象的内部字段依然可能被修改。使用时要有清晰的预期。可选项的配合同样关键可选属性章节 展示了带默认值的解构写法type X { a: number; b?: number; }; const x ({ a, b 100 }: X) a b;修饰符的实战组合修饰符可以自由组合例如把某个类型的所有属性变为可选且只读type ReadonlyPartialT { readonly [P in keyof T]?: T[P]; };而去除可选标记则用-?语法与-readonly对称type RequiredT { [P in keyof T]-?: T[P] };-前缀的作用就是移除修饰符它同时适用于readonly与?这也是 TypeScript 内置工具类型RequiredT和Mutable类工具的实现原理。键重映射Key Remapping用 as 子句改写属性名除了变换属性值和修饰符映射类型还可以改写属性名本身。[P in keyof T as 新键表达式]中的as子句允许你对每个键做二次变换通常与模板字面量类型配合使用。类型系统探索章节 给出了一个非常典型的键重映射示例type JType { [Property in keyof Type as prefix_${string Property}]: () Type[Property]; }; type X { a: string; b: number; }; type Y JX;这里的关键语法点as之后的模板字面量prefix_${string Property}为每个键拼接prefix_前缀string Property的作用是把Property收窄到string子类型确保它能安全地插值进模板字符串因为键也可能包含symbol或number类型的索引签名键值类型() Type[Property]把每个原始属性的值包装成一个返回该值的函数。展开后Y等价于type Y { prefix_a: () string; prefix_b: () number; };这是映射类型最强大的形态键、值、修饰符三者皆可编程化变换。键重映射的典型应用场景包括给 API 响应字段统一加前缀如api_、db_把snake_case键改写为camelCase键根据键名过滤掉私有字段as表达式返回never即剔除该键。与模板联合类型结合在类型系统中生成字符串字面量键重映射中出现的模板字面量类型本身也是类型系统的文本运算能力。模板联合类型章节 展示了如何在类型层面组合字符串type Status active | inactive; type Products p1 | p2; type ProductId id-${Products}-${Status}; // 展开结果id-p1-active | id-p1-inactive | id-p2-active | id-p2-inactive当模板字面量中嵌入的是联合类型时TypeScript 会自动做笛卡尔积展开生成全部组合。将这一能力嵌入映射类型的as子句就可以在编译期批量生成规范化键名例如为每个状态机状态生成带前缀的 action typetype Action create | update | delete; type Entity user | order; type ActionType entity/${Entity}/${Action}; // entity/user/create | entity/user/update | ... 共 6 种组合 type ActionsType { [K in keyof Type as on${Capitalizestring K}]: () void; };后者借助内置的CapitalizeT工具类型见 类型操作章节 中的Capitalize、Uppercase、Lowercase、Uncapitalize系列把click变成onClick是事件回调对象映射的常见写法。映射类型是内置工具类型的实现根基理解映射类型后会发现 TypeScript 内置的众多工具类型本质上就是一组预置好的映射。类型操作章节 的 Utility Types 列表可以直接用映射类型的眼光重新审视PartialT即{ [P in keyof T]?: T[P] }—— 全部属性可选RequiredT即{ [P in keyof T]-?: T[P] }—— 全部属性必填ReadonlyT即{ readonly [P in keyof T]: T[P] }—— 全部属性只读RecordK, T用联合键K构建一个所有值都是T的对象类型。PartialPerson的展开结果在章节中有明确标注type Person { name: string; age: number; }; type A PartialPerson; // { name?: string | undefined; age?: number | undefined; }ReadonlyT与RecordK, T的示例type Person { name: string; age: number; }; type A ReadonlyPerson; const a: A { name: Simon, age: 17 }; a.name John; // Invalid只读属性不允许重新赋值type Product { name: string; price: number; }; const products: Recordstring, Product { apple: { name: Apple, price: 0.5 }, banana: { name: Banana, price: 0.25 }, }; console.log(products.apple); // { name: Apple, price: 0.5 }因此当你在项目中看到Partial、Readonly、Required时其实正在使用映射类型而当你需要比内置工具更定制化的变换时直接手写[P in keyof T]即可获得同等甚至更强的表达能力。映射类型与类型操作体系的定位映射类型并非孤立存在它是 TypeScript从类型创建类型这一更大体系中的一环。类型操作章节 将类型构造方式归纳为四类交集类型合并多个类型的成员联合类型|类型可以是若干候选之一映射类型遍历并变换现有类型的属性条件类型extends ? :根据条件在类型之间选择常配合infer提取子类型。例如其中的ExtractParamT通过条件类型提取函数参数类型type ExtractParamT T extends (param: infer P) any ? P : never; type MyFunction (name: string) number; type ParamType ExtractParamMyFunction; // string在项目实践中映射类型常与条件类型、模板字面量类型协同作战——映射负责遍历和变换条件类型负责分支决策模板字面量负责键名与字符串的生成。实战场景用映射类型解决真实问题场景一将实体类型转换为表单校验模型type User { name: string; email: string; age: number; }; // 每个字段变为值 错误信息的结构 type FieldStateT { [K in keyof T]: { value: T[K]; error: string | null; }; }; type UserForm FieldStateUser; // { name: { value: string; error: string | null }; email: {...}; age: {...} }场景二统一为接口响应追加元数据字段type WithMetaT, M { [K in keyof T]: T[K]; } { meta: M; }; type ApiUser WithMetaUser, { fetchedAt: string };场景三将数据库行对象映射为前端可编辑表单部分字段可选type EditableT { [K in keyof T]?: T[K]; }; type UserDraft EditableUser; // 所有字段均可选适合表单草稿这些模式共同体现了映射类型的设计哲学类型层面的批量操作不需要运行时开销全部变换发生在编译期最终产物是精确的、可被编辑器与编译器校验的类型约束。小结映射类型通过keyof获取属性集合、用[P in keyof T]遍历属性、用T[P]索引访问原值类型再辅以readonly/-readonly、?/-?修饰符与as键重映射构成了一个完整的类型工厂体系。它既是Partial、Readonly、Required、Record等内置工具类型的底层实现也是你在面对 DTO 转换、表单模型、事件回调映射、API 键名规范化等场景时最值得优先考虑的类型编程手段。深入学习本主题建议按以下路径阅读仓库内容映射类型英文原版 与 西班牙语版掌握核心语法与示例映射类型修饰符掌握readonly、-readonly、?索引签名理解可映射的键类型及数字/字符串索引转换模板联合类型结合模板字面量做键名编程类型操作总览将映射类型放入从类型创建类型的完整体系并对照全部内置工具类型。赞分享文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载相关推荐The Concise TypeScript Book映射类型Mapped Types实战指南The Concise TypeScript Book映射类型Mapped Types实战指南 映射类型是 TypeScript 类型系统中最强大的类型变文档教程TypeScript 映射类型Mapped Types实战指南——The Concise TypeScript Book 核心章节解读TypeScript 映射类型Mapped Types实战指南——The Concise TypeScript Book 核心章节解读 本文依据开源书籍《T文档教程《The Concise TypeScript Book》精读Mapped Types 映射类型完全指南《The Concise TypeScript Book》精读Mapped Types 映射类型完全指南 映射类型Mapped Types是 TypeSc文档教程上一篇开源项目常见问题解决方案js-plugin-circliful下一篇ARIS 输出语言协议Output Language Protocol实战指南多语言 Agent 输出中的语言检测、本地化边界与机器解析保护创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考