《The Concise TypeScript Book》精讲:TypeScript 映射类型修饰符(Mapped Type Modifiers)完全指南
文档教程【免费下载链接】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允许我们基于既有类型逐属性生成新类型而映射类型修饰符Mapped Type Modifiers则是在这个过程中控制每个属性只读性与可选性的关键语法。本文以开源仓库 typ/typescript-book 中 mapped-type-modifiers.md 章节为骨架结合同书 mapped-types.md、readonly-properties.md、optional-properties.md 与 type-manipulation.md 等章节系统讲解readonly、-readonly、?三个修饰符的语法、语义与实战组合读完后你将能够手写ReadonlyT、PartialT等工具类型的等价实现并在自己的类型体系中自如地加锁与解锁属性。一、前置基础先理解映射类型本身在讨论修饰符之前必须先明确它们作用的载体——映射类型。按照本书 mapped-types.md 章节的定义Mapped Types 允许你基于一个既有类型通过映射函数逐属性变换创建出新类型。通过映射既有类型你可以创建以不同格式表达相同信息的新类型。创建映射类型需要两步用keyof取出既有类型的全部属性键再用索引签名[P in keyof T]遍历这些键并用索引访问类型T[P]取出每个属性的原始类型进行变换。原章节给出的核心示例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], };这里MyMappedTypeT遍历T的每个属性P把每个属性的类型T[P]包装成数组T[P][]于是MyNewType与MyType表达相同的信息但每个属性的形态都从标量变成了数组。映射类型修饰符就是在这段[P in keyof T]的声明处附加readonly、?等标记从而在复制结构的同时改变属性的可变性与可选性。二、三个核心修饰符总览本章节 mapped-type-modifiers.md 明确指出TypeScript 的映射类型修饰符共有三类能力修饰符语义作用readonly或readonly在映射结果中把属性标记为只读属性只能读取不能重新赋值-readonly在映射结果中把属性恢复为可变解除上层类型或映射带来的只读约束?在映射结果中把属性标记为可选属性可以缺省赋值的对象可以不提供该键注意前缀是显式写法readonly与readonly完全等价而-前缀是移除语义只能作用于映射类型内部用于把已有修饰符剥离掉。下面逐一展开。三、readonly/readonly批量加只读锁原章节给出的第一个示例type ReadOnlyT { readonly [P in keyof T]: T[P] }; // All properties marked as read-only这个泛型类型接收任意对象类型T遍历其全部属性并在每个属性前加上readonly。它的效果等价于把T的每个属性都用readonly重新声明一遍。回顾本书 readonly-properties.md 章节对只读属性的解释使用readonly修饰符可以阻止对属性的写入它确保属性不能被重新赋值但不提供完全不可变total immutability的保证。也就是说readonly只约束引用层面的赋值不阻止属性内部如嵌套对象、数组元素的修改。这是使用只读类型时最容易踩的坑readonly是浅层的。readonly是它的显式等价形式在需要强调添加语义与后面的-对应时使用type ReadOnlyExplicitT { readonly [P in keyof T]: T[P] }; // 与 readonly 写法完全等价下面演示实际使用效果type User { name: string; age: number; }; type ReadonlyUser ReadOnlyUser; // 等价于 { readonly name: string; readonly age: number; } const user: ReadonlyUser { name: Simon, age: 17 }; user.name John; // 编译错误无法为只读属性赋值值得注意的是readonly修饰符同样适用于索引签名。在 readonly-properties.md 中给出了如下声明形式type K { readonly [index: number]: string; };这说明只读修饰符不仅可以加在具名属性上也可以加在索引签名上从而锁定整个字典不可被改写。四、-readonly解除只读实现MutableT原章节的第二个示例展示了反向操作type MutableT { -readonly [P in keyof T]: T[P] }; // All properties marked as mutable-readonly表示移除只读修饰符它把输入类型中所有readonly属性全部还原为可变属性。这在处理来自外部库、as const断言或ReadonlyT包装过的类型时非常实用type Config { readonly apiUrl: string; readonly retries: number; }; type MutableConfig MutableConfig; // 等价于 { apiUrl: string; retries: number; } const config: MutableConfig { apiUrl: https://api.example.com, retries: 3 }; config.retries 5; // 合法MutableConfig 的属性已可写语法上readonly与-readonly是一对添加/移除操作?同样存在对应的-?移除形式详见第六节。注意-前缀必须紧跟在属性声明位置且-readonly只能出现在映射类型中不能用于interface或普通对象类型。五、?批量将属性变为可选原章节的第三个示例type MyPartialT { [P in keyof T]?: T[P] }; // All properties marked as optional?修饰符把T的每个属性都标记为可选。这与 optional-properties.md 章节中在属性名末尾加问号?即声明可选属性的规则一脉相承type X { a: number; b?: number; // Optional };映射版本MyPartialT则把每个属性都可选这件事自动化。它的典型使用场景包括配置合并用户只提供部分配置、表单部分更新PATCH 语义、测试替身等type Settings { theme: string; fontSize: number; showLineNumbers: boolean; }; type PartialSettings MyPartialSettings; // 等价于 { theme?: string; fontSize?: number; showLineNumbers?: boolean; } const patch: PartialSettings { fontSize: 14 }; // 只更新一个字段合法配合可选属性的默认值技巧同样出自 optional-properties.md可以在消费方优雅地处理缺省值const mergeSettings ({ theme dark, fontSize 16, showLineNumbers true }: PartialSettings) ({ theme, fontSize, showLineNumbers, });六、组合使用与-?同时操控两个维度三个修饰符之间可以自由组合。最典型的组合是既只读又可选这正是内置ReadonlyPartialT的效果type ReadonlyPartialT { readonly [P in keyof T]?: T[P] }; // 每个属性readonly 且 optional反过来映射类型也支持-?来移除可选性把可选属性恢复为必填type MyRequiredT { [P in keyof T]-?: T[P] }; // 移除 ?所有属性必填这一写法与-readonly对称-前缀统一表示剥离修饰符。RequiredT工具类型的标准实现正是基于-?的参见下文与 type-manipulation.md 中RequiredT的说明。同时移除只读与可选type ConcreteT { -readonly [P in keyof T]-?: T[P] }; // 所有属性可变且必填一个完整的读写权限变换实战示例type Draft { title?: string; body?: string; }; // 发布前要求所有字段齐全-?并且一旦发布不可再改readonly type Published { readonly [P in keyof Draft]-?: Draft[P] }; // 等价于 { readonly title: string; readonly body: string; } const post: Published { title: Hello, body: World }; post.title Hi; // 编译错误readonly七、与内置工具类型的关系ReadonlyT、PartialT、RequiredT的本质本书 predefined-conditional-types.md 与 type-manipulation.md 两个章节列出了大量内置工具类型其中与映射类型修饰符直接相关的有三个内置工具类型文档定义本质映射类型等价实现ReadonlyT将 T 的所有属性设为 readonly{ readonly [P in keyof T]: T[P] }PartialT将 T 的所有属性设为可选{ [P in keyof T]?: T[P] }RequiredT将 T 的所有属性设为必填{ [P in keyof T]-?: T[P] }其中Partial与Required互为逆操作Readonly与手写的MutableT互为逆操作。这正是本章节三个示例ReadOnly、Mutable、MyPartial的深层意义它们实际上是在重新发明语言内置的工具类型让你理解工具类型不是魔法而是映射类型 修饰符的语法糖。在 type-manipulation.md 中可以看到这些工具类型的具体使用示例type Person { name: string; age: number; }; type A PartialPerson; // { name?: string | undefined; age?: number | undefined; } type B Required{ name?: string; age?: number }; // { name: string; age: number; } type C ReadonlyPerson; const a: C { name: Simon, age: 17 }; a.name John; // Invalid注意一个细节PartialT在严格模式strictNullChecks 开启下会为每个可选属性附加| undefined。这源于可选属性在严格模式下意味着可能缺失也可能为 undefined的语言语义与本书 strictnullchecks.md 章节所讲的严格空值检查行为一致。八、深入原理同态映射、修饰符保留与浅层只读8.1 同态映射修饰符默认被保留当映射类型直接使用[P in keyof T]不附加任何修饰符时TypeScript 会原样保留输入类型T中已有的readonly与?修饰符。这种保形复制的映射被称为同态homomorphic映射。也就是说type CopyT { [P in keyof T]: T[P] }; type Source { readonly id: number; label?: string; }; // CopySource 仍是 { readonly id: number; label?: string; } // 只读与可选修饰符都被保留了下来如果希望复制结构的同时强制改变修饰符就必须显式使用/-前缀或直接书写修饰符如readonly、?。这正是-readonly、-?存在的意义——默认行为是保留主动移除才需要减号。8.2readonly的浅层性不是深度不可变再次强调 readonly-properties.md 中的警告readonly不提供任何完全不可变的保证。例如type ReadonlyUser { readonly profile: { nickname: string } }; const user: ReadonlyUser { profile: { nickname: simon } }; user.profile { nickname: other }; // 编译错误profile 是 readonly user.profile.nickname other; // 合法嵌套对象内部仍然可写如果需要深度只读必须递归地让每个嵌套属性都经过映射处理可结合条件类型实现递归映射这不是单个readonly修饰符能完成的。8.3 修饰符只能作用于映射类型内部readonly、-readonly、?、-?这些映射修饰符只能出现在映射类型{ [P in ...] ... }中。在普通对象类型、interface中书写-readonly或-?会直接报语法错误。interface中可用的只有声明形式的readonly与?见 optional-properties.md 与 readonly-properties.md。8.4 键重映射修饰符之外的第三种变换除了修饰符映射类型还支持用as子句重写键名这是映射类型三大变换能力改修饰符、改类型、改键名之一。在 exploring-the-type-system.md 的 Type Assertion 小节中给出了一个将修饰符、键重映射与模板字面量类型结合的示例type JType { [Property in keyof Type as prefix_${string Property}]: () Type[Property]; }; type X { a: string; b: number; }; type Y JX; // 等价于 { // prefix_a: () string; // prefix_b: () number; // }这里as \prefix_${string Property}把每个键重命名为带prefix_前缀的新键值类型则从属性类型变换为返回该类型的函数。虽然这不是修饰符的职责但理解as键重映射能让读者把映射类型这一整套能力keyof遍历 T[P]取类型 修饰符改可变性 as 改键名完整串起来。九、实战用一个综合案例串联全部修饰符下面把本章节三个示例改造成一个贴近真实项目的场景——数据模型的草稿可变可选→ 冻结只读必填生命周期// 1. 基础模型所有字段必填、可写 type Article { title: string; content: string; tags: string[]; }; // 2. 草稿态字段全部可选方便增量编辑等价于 PartialArticle type ArticleDraft { [P in keyof Article]?: Article[P] }; // 3. 发布态字段全部必填且只读组合使用 ? 移除与 readonly 添加 type PublishedArticle { readonly [P in keyof Article]-?: Article[P] }; // 4. 如果从外部如 API 响应或 as const 常量拿到的是只读类型 // 用 -readonly 解除锁便于在本地修改 declare const fetched: { readonly title: string; readonly content: string; readonly tags: string[] }; type MutableArticle { -readonly [P in keyof typeof fetched]: (typeof fetched)[P] }; // 5. 使用 const draft: ArticleDraft { title: Draft title }; // 合法其余字段可选 const published: PublishedArticle { title: T, content: C, tags: [ts] }; published.title T2; // 编译错误readonly这个案例中?、-?、readonly、-readonly四种映射修饰符全部登场分别对应放宽输入约束与收紧输出约束两种方向展示了映射类型修饰符在数据流边界表单、持久化、接口层上的典型用法。十、小结与延伸阅读映射类型修饰符是 TypeScript 类型系统的格式化工具readonly/readonly批量加只读锁-readonly批量解锁?批量放宽为可选-?批量收紧为必填默认的同态映射会保留既有修饰符显式的前缀操作符则用于强制改变它们。掌握这四个操作符你就掌握了ReadonlyT、PartialT、RequiredT等内置工具类型的实现原理能够在任何需要以类型为输入、以类型为输出的场景中写出精确的类型变换。本文对应的原文档位于 mapped-type-modifiers.md它在全书的目录结构中紧随 mapped-types.md见 table-of-contents.md 第 38、39 章。建议按以下顺序继续深入mapped-types.md映射类型的基础语法keyof[P in keyof T]T[P]readonly-properties.md 与 optional-properties.md只读与可选属性的声明语法type-manipulation.mdPartial、Required、Readonly等内置工具类型的完整清单与用法exploring-the-type-system.md包含as键重映射在内的更高级类型操作predefined-conditional-types.md条件类型视角下的工具类型速查表。赞分享文档教程【免费下载链接】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点击查看免费下载相关推荐BabelDOC突破性智能排版保留的PDF文档翻译解决方案BabelDOC突破性智能排版保留的PDF文档翻译解决方案 BabelDOC是一款专为学术和商业文档设计的智能翻译工具通过先进的排版分析和结构重建技术在保人工智能AI 应用NLP计算机视觉The Concise TypeScript Book 精讲函数返回类型推断Type from Func Return原理与实战The Concise TypeScript Book 精讲函数返回类型推断Type from Func Return原理与实战 本篇技术指南以开源仓库文档教程poly_data进阶技巧使用process_live实现实时数据流处理poly_data进阶技巧使用process_live实现实时数据流处理 poly_data是一个强大的Polymarket数据检索工具能够高效获取、处理和文档教程上一篇unified国际化支持多语言内容处理完整方案下一篇前端开发者必备You-Dont-Need-JavaScript项目完全使用手册创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

从零实现ID3与C4.5决策树:贷款审批规则提取实战

从零实现ID3与C4.5决策树:贷款审批规则提取实战

1. 项目背景与整体思路最近在做贷款审批的规则梳理,我把 ID3 和 C4.5 两个经典决策树算法从零写了一遍,用一份贷款申请样本数据把建树、预测、剪枝和调参的完整流程重新跑通。先说结论:今天做风控建模,XGBoost、LightGBM 这些模型…

2026/9/24 20:16:37 阅读更多 →
模仿不是抄袭:一套从拆解对标到原创的低成本进阶方法论

模仿不是抄袭:一套从拆解对标到原创的低成本进阶方法论

先说明一句:这篇文章没有要劝你“抄”谁,恰恰相反,我特别想聊清楚一件事——为什么很多人一听到“模仿”就皱眉,觉得那是没本事的人才会干的事,但实际上,模仿恰恰是成本最低、见效最快的进阶方式&#xff0…

2026/9/24 20:16:37 阅读更多 →
工业边缘计算实战:人工智能+产线改造的第一站与避坑指南

工业边缘计算实战:人工智能+产线改造的第一站与避坑指南

这几年做工厂智能化改造的朋友应该都有同感:大家聊“人工智能”聊得火热,但真正落到车间里,最先让你挠头的往往不是算法,而是数据怎么接、模型往哪放、掉线了怎么办。我在这行摸爬滚打久了,越来越确信一个判断——“人…

2026/9/24 20:16:37 阅读更多 →

最新新闻

AI工程全景地图:六步构建从数据到价值的落地路径

AI工程全景地图:六步构建从数据到价值的落地路径

1. 为什么突然都在说 AI 工程这几年“AI 工程”这个词出现频率越来越高,但你要是真去问一句“AI 工程到底是什么”,能一句话说清楚的人其实不多。我见过不少团队,模型训练得挺溜,一到上线就翻车,不是推理延迟压不下来&…

2026/9/24 20:48:59 阅读更多 →
jsonschema实战:为JSON数据立规矩的Python校验库

jsonschema实战:为JSON数据立规矩的Python校验库

我们天天和数据打交道,但真正让你头疼的往往不是“数据对不对”,而是“数据是不是你要的那个结构”。JSON 格式灵活得让人又爱又恨,前端传参少个字段、API 响应多了个 null、配置文件类型悄悄从 int 变成 string,这些坑想必大家都…

2026/9/24 20:48:59 阅读更多 →
Codex Token消耗优化:两个开源工具让账单减半

Codex Token消耗优化:两个开源工具让账单减半

先说结论:Codex 确实好用,但它烧起 Token 来也真的一点都不含糊。我重度用了几个月之后,账单上的数字一度让我怀疑是不是把 API Key 泄露了。后来我才意识到,问题不在于 Codex 本身有多能吃,而在于我们喂给它的“上下文…

2026/9/24 20:48:59 阅读更多 →
GPT金融AI量化投资实战:从信息提取到策略辅助的工程化探索

GPT金融AI量化投资实战:从信息提取到策略辅助的工程化探索

1. 从标题出发:这个项目到底在做什么“开启GPT技术与金融AI投资探索之旅”这个标题,乍一看像是某个课程或者训练营的宣传语,但如果你真的动手去拆,会发现它其实指向一个非常具体的技术落地场景:用大语言模型的能力去辅…

2026/9/24 20:48:59 阅读更多 →
AI室内设计会改结构吗?四款工具实测与避坑指南

AI室内设计会改结构吗?四款工具实测与避坑指南

1. 从一张户型图说起:AI室内设计到底动了什么很多人第一次用AI做室内设计,心里都揣着同一个疑问:我把户型图丢进去,它会不会自作主张把承重墙砸了、把窗户挪了、把卫生间改到客厅中间?这个担心不是多余的。我前后用四款…

2026/9/24 20:48:59 阅读更多 →
使用 @openuidev/devtools 调试 OpenUI 应用:Inspect 事件面板与 Debug 工作台实战指南

使用 @openuidev/devtools 调试 OpenUI 应用:Inspect 事件面板与 Debug 工作台实战指南

使用 openuidev/devtools 调试 OpenUI 应用:Inspect 事件面板与 Debug 工作台实战指南 【免费下载链接】openui The Open Standard for Generative UI 项目地址: https://gitcode.com/gh_mirrors/openui1/openui openuidev/devtools 是 OpenUI 生态中的开发期…

2026/9/24 20:47:58 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →