首页/新闻资讯/正文详情

The Concise TypeScript Book 精读:映射类型修饰符(Mapped Type Modifiers)全解

发布时间:2026/9/26 4:01:54 来源:云帆数科 栏目:资讯中心
The Concise TypeScript Book 精读:映射类型修饰符(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点击查看免费下载映射类型修饰符是 TypeScript 在「映射类型」基础上提供的一组类型级开关让你在对既有类型逐属性变换时同步调整每条属性的只读性与可选性。本指南以开源仓库 The Concise TypeScript Book 的 es 版映射类型修饰符章节 为骨架结合仓库中映射类型、只读属性、可选属性等相邻章节与类型系统源码级说明带你从语法到实战完整掌握readonly、-readonly、?三种修饰符的用法、加减法语法、与内置工具类型的关系及其边界限制。读完你将能够自己写出ReadOnlyT、MutableT、MyPartialT这类可复用的类型工具并理解ReadonlyT、PartialT、RequiredT等标准库工具类型的底层实现原理。一、先理解载体映射类型Mapped Types修饰符本身不能单独使用它必须出现在映射类型的遍历语法之中。所谓映射类型就是基于一个既有类型通过keyof取出其全部键再逐一对每个键的取值类型进行变换最终产出一个全新类型。仓库的 映射类型章节 给出了最典型的骨架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], };这里[P in keyof T]是遍历语法P依次取到T的每个键右侧T[P]索引访问类型取出该键对应的值类型再包装成数组。于是MyType的foo: string与bar: number被映射成foo: string[]与bar: number[]——信息不变形态改变这正是映射类型的核心价值。而映射类型修饰符则负责在遍历过程中额外控制每条属性的readonly只读与?可选属性。它们写在属性名之前、与[P in keyof T]同处一个位置type X { readonly [P in keyof T]: T[P] }; // 修饰符位于遍历语法之前二、三种核心修饰符语法与语义原文档将修饰符归纳为三类以下逐一展开。2.1readonly/readonly把属性变为只读在映射类型中为每条属性加上readonly即可让结果类型的全部属性不可重新赋值type ReadOnlyT { readonly [P in keyof T]: T[P] }; // All properties marked as read-onlyreadonly与readonly语义完全等价——表示「显式添加该修饰符」是冗余但更明确、可读性更好的写法type ReadOnlyT { readonly [P in keyof T]: T[P] }; // 与上一写法等价两者都是添加只读约束。若省略前缀直接写readonlyTypeScript 同样视为添加。2.2-readonly把属性变回可变-readonly是readonly的逆操作用于移除既有类型上的只读标记让属性恢复可写type MutableT { -readonly [P in keyof T]: T[P] }; // All properties marked as mutable注意-只能配合修饰符使用如-readonly、-?单独写-本身没有意义。/-前缀的引入TypeScript 2.8 起使得修饰符不再是单向追加而是可加可删这也是实现RequiredT等工具类型的语法基础。2.3?把属性标记为可选在映射类型中加入?会让结果类型的所有属性变为可选即属性可以缺失type MyPartialT { [P in keyof T]?: T[P] }; // All properties marked as optional这里的?与普通对象类型中b?: number的语义一致——仓库的 可选属性章节 中特别说明可选属性可通过解构赋默认值来兜底type X { a: number; b?: number; }; const x ({ a, b 100 }: X) a b;同样地-?即-加?可以移除可选标记强制所有属性必填这正是内置RequiredT的做法type MyRequiredT { [P in keyof T]-?: T[P] }; // All properties marked as required三、原文档完整示例三种工具类型一次到位原文档用三个并排定义的泛型工具类型直观展示了三种修饰符的独立用法这是本主题最核心的实操片段完整保留如下type ReadOnlyT { readonly [P in keyof T]: T[P] }; // All properties marked as read-only type MutableT { -readonly [P in keyof T]: T[P] }; // All properties marked as mutable type MyPartialT { [P in keyof T]?: T[P] }; // All properties marked as optional配合一个实际类型走一遍全流程type Person { readonly name: string; // 原本就是只读 age: number; }; // 1) 全部变成只读 type FrozenPerson ReadOnlyPerson; // { readonly name: string; readonly age: number; } // 2) 全部变回可变含原本 readonly 的 name type EditablePerson MutablePerson; // { name: string; age: number; } // 此时 name 可以被重新赋值 // 3) 全部变成可选 type PartialPerson MyPartialPerson; // { readonly name?: string; age?: number; }一个关键观察MutableT能同时把原本声明为readonly的属性解除只读这正是-readonly存在的原因——单靠readonly只能加不能减有了-前缀后映射类型才具备双向调整能力。四、组合使用同时控制只读与可选修饰符不是互斥的它们可以自由叠加在同一映射类型上形成四种组合// 全部只读 全部可选 type ReadonlyPartialT { readonly [P in keyof T]?: T[P] }; // 全部可变 全部可选等价于去掉 readonly 的 Partial type MutablePartialT { -readonly [P in keyof T]?: T[P] }; // 全部只读 全部必填 type ReadonlyRequiredT { readonly [P in keyof T]-?: T[P] }; // 全部可变 全部必填等价于 RequiredMutableT type MutableRequiredT { -readonly [P in keyof T]-?: T[P] };这种组合能力在实战中非常常见例如「接口返回的字段都是必填但前端修改表单时希望它们全部变为可选且可变」一条映射类型即可完成type ApiUser { readonly id: number; readonly name: string; readonly email: string; }; // 表单编辑态去掉只读、允许部分字段缺失 type EditableForm { -readonly [P in keyof ApiUser]?: ApiUser[P] }; // { id?: number; name?: string; email?: string; }五、与内置工具类型的对应关系你可能已经注意到上面手写的ReadOnlyT、MyPartialT与 TypeScript 标准库内置的ReadonlyT、PartialT几乎一模一样。事实上映射类型修饰符正是这些内置工具类型的底层实现机制。仓库的 类型操作章节 系统整理了这些内置工具类型的语义PartialT构造一个把T所有属性都设为可选的类型RequiredT构造一个把T所有属性都设为必填的类型ReadonlyT构造一个把T所有属性都设为只读的类型其效果与readonly [P in keyof T]完全一致。例如ReadonlyT的等价手写实现就是我们上面定义的ReadOnlyT而RequiredT对应{ [P in keyof T]-?: T[P] }。仓库 只读属性章节 还展示了readonly在普通类型与索引签名中的表现interface Y { readonly a: number; } type X { readonly a: number; }; type J Readonly{ a: number; }; type K { readonly [index: number]: string; // 只读索引签名 };需要特别强调的是J Readonly{ a: number }与手写{ readonly a: number }得到的类型结构完全相同——因为在结构类型系统下仓库 探索类型系统章节 有专述类型由结构决定而非声明方式决定所以「用内置工具」和「手写修饰符」在编译层面等价你可以按可读性任选其一。六、实战场景与注意事项6.1 从 API 响应派生「不可变」快照后端返回的领域对象往往在业务层不应被随意改写可以把它包装为只读版本作为跨模块传递的只读快照type ApiOrder { id: string; items: string[]; total: number; }; type ImmutableOrder ReadonlyApiOrder; // { readonly id: string; readonly items: string[]; readonly total: number; } function render(order: ImmutableOrder) { // order.total 0; // 编译错误Cannot assign to total because it is a read-only property }6.2 解除第三方库类型的只读约束当你拿到一个被ReadonlyT包裹的入参类型又需要在本地做变更时-readonly就是唯一的「解药」type LockedConfig Readonly{ host: string; port: number }; // 本地可变副本 type MutableConfig { -readonly [P in keyof LockedConfig]: LockedConfig[P] }; // { host: string; port: number }6.3 注意只读是类型层面的契约不是运行时保证原文档及 只读属性章节 都反复强调一个边界readonly只保证编译期不能重新赋值并不提供任何运行时不可变性不产生任何运行时效果。例如type Config Readonly{ retries: number }; const cfg: Config { retries: 3 }; // cfg.retries 5; // 编译错误 // 但类型断言可以绕过运行时并不阻止写入 (cfg as { retries: number }).retries 5; // 合法同理readonly是浅层的它只禁止对属性本身重新赋值不禁止修改属性内部的内容如数组元素、嵌套对象字段。若要深度不可变需要递归组合ReadonlyT或借助as const等额外手段这超出了修饰符本身的职责范围。6.4 可选属性与strictNullChecks的联动映射出可选属性后在访问时 TypeScript 会要求先做存在性判断仓库 strictnullchecks 章节 对此有专门论述。因此由?派生出的类型在读取字段时通常需要配合if (obj.field ! undefined)或可选链obj?.field这是使用MyPartialT类工具时的常见伴生约束。七、进阶延伸修饰符不是唯一变换维度掌握readonly、?、/-之后你会自然联想到一个更广泛的问题既然遍历[P in keyof T]可以修改属性特性是否也能修改键本身答案是肯定的——在更高级的映射类型中可以使用as子句对键做重映射如[P in keyof T as NewKey]从而筛选、改名或联合模板字面量生成新键。但仓库本主题章节并未涉及该语法此处仅作为方向提示修饰符解决的是「属性的状态」as重映射解决的是「键的身份」两者叠加即可写出Pick、Omit、Record这类更复杂的标准工具类型它们的语义说明同样收录于 类型操作章节。八、小结语法位置修饰符写在映射类型遍历语法[P in keyof T]之前。readonly/readonly为所有属性添加只读约束-readonly反向移除。?将属性标记为可选-?将可选移除、恢复必填。组合自由readonly与?可任意搭配配合/-实现四种象限。与标准库同源ReadonlyT、PartialT、RequiredT的底层就是这些修饰符手写与内置在结构类型系统下等价。边界清晰readonly是浅层、编译期约束不提供运行时不可变性。掌握了这组修饰符你不仅能读懂标准库工具类型的实现还能按需定制出自己的类型变换工具——这正是 The Concise TypeScript Book 将「映射类型」与「映射类型修饰符」设为相邻章节第 38、39 节的用意所在。想进一步巩固可回看仓库的 映射类型章节、只读属性章节 与 可选属性章节并用 TypeScript Playground 或本地tsc逐一验证上文所有示例。赞分享文档教程【免费下载链接】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》精讲TypeScript 映射类型修饰符Mapped Type Modifiers完全指南《The Concise TypeScript Book》精讲TypeScript 映射类型修饰符Mapped Type Modifiers完全指南 映射文档教程kkFileView 如何在 GitHub Actions 中配置 PR 与 Nightly 自动运行预览 E2E 回归kkFileView 如何在 GitHub Actions 中配置 PR 与 Nightly 自动运行预览 E2E 回归 kkFileView 仓库已经内置了两文档教程Windmill App Builder 组件扩展指南从零添加一个前端 App 组件Windmill App Builder 组件扩展指南从零添加一个前端 App 组件 导读 Windmill 是一个开源开发者平台其内置的 App Buil文档教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

OpenClaw本地部署实战:Cherry Studio+Ollama Cloud两小时跑通智能体
OpenClaw本地部署实战:Cherry Studio+Ollama Cloud两小时跑通智能体

上周帮一个做运营的朋友装OpenClaw,她提了两个硬性要求:两小时内必须跑通,而且别给她整一堆黑框框的命令行。最后实际用时一小时五十分钟,全程用到的核心组合就是本地部署OpenClaw,再配合Cherry Studio和Ollama Cloud。… · 2026/9/26 4:01:54

实战指南:从零构建 MCP 架构下的 Agentic RAG 系统,无第三方 MCP Server 的 TaoToken 配置骨架
实战指南:从零构建 MCP 架构下的 Agentic RAG 系统,无第三方 MCP Server 的 TaoToken 配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 4:01:48

GPT-6 Astra 发布后,Mac 上怎么用 TaoToken 配好 Computer Use Agent 的 config.toml 骨架
GPT-6 Astra 发布后,Mac 上怎么用 TaoToken 配好 Computer Use Agent 的 config.toml 骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 4:01:48

video-use:视频处理全链路自动化工具链设计与实践
video-use:视频处理全链路自动化工具链设计与实践

1. 项目概述:一个围绕视频处理全链路的实用型工具集命名逻辑“video-use”这个名称乍看像随手打的标签,但放在当前技术生态里,它其实精准概括了一类高频、刚需、却长期缺乏统一命名的实践场景——不是单纯播放视频,也不是只做剪辑… · 2026/9/26 5:26:31

5分钟上手全栈AI智能体开发:gemini-fullstack-langgraph-quickstart架构详解与实战指南
5分钟上手全栈AI智能体开发:gemini-fullstack-langgraph-quickstart架构详解与实战指南

用五分钟就可以掌握全栈人工智能智能体的开发技能, 接下来会对相关的架构展开详细的说明, 并且提供实际的作战指南。这里是免费的下载连接。这个操作需要使用版本号为2.5的系统, 同时还必须包含其他相关的配置步骤。项目的所在位置是, 项目地址。你是不是还在因为把AI智能体的前… · 2026/9/26 5:26:25

STM32 SBUS解析:DMA+IDLE中断实现工业级稳定接收
STM32 SBUS解析:DMA+IDLE中断实现工业级稳定接收

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 5:26:12

DeskcommCRM深度解析:从设计思路到二次开发实践
DeskcommCRM深度解析:从设计思路到二次开发实践

早上刚来的那批线索,销售还没顾上打第一通电话,运营那边就发来消息问转化情况;客户在微信上问了句价格,等到客服切换好几个窗口找到聊天记录时,人已经去对比别家了。这种场景,做销售和客户运营的朋友应该都… · 2026/9/26 5:26:12

ArcGIS读取Excel失败:ACE引擎注册与位数匹配详解
ArcGIS读取Excel失败:ACE引擎注册与位数匹配详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 5:26:12

订单超时自动取消方案深度拆解:业务设计、技术选型与避坑指南
订单超时自动取消方案深度拆解:业务设计、技术选型与避坑指南

做了这么多年交易系统,订单超时自动取消这个场景可以说是每个电商、外卖、票务平台都绕不开的标配需求。表面看就是“到点把未支付订单关掉”,但真往深了做,你会发现它牵扯到状态机设计、延迟消息可靠性、并发竞态、库存回补等一系列问题&… · 2026/9/26 5:26:12

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码