The Concise TypeScript Book 精读:擦除的结构化类型(Erased Structural Types)与鸭子类型式类型系统
The Concise TypeScript Book 精读擦除的结构化类型Erased Structural Types与鸭子类型式类型系统【免费下载链接】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本文以 erased-structural-types.md 为骨架系统讲解 TypeScript 结构化类型系统的判定规则与擦除语义对象不必须显式声明实现某个接口只要形状结构满足要求即可互相兼容同时这些类型约束在编译后会被完全擦除不产生任何运行时开销。读完本文你将理解 TypeScript 类型兼容性的底层判定逻辑、它与 JavaScript 鸭子类型的关系、以及类型擦除带来的实际工程影响。一、核心概念对象不需要显式匹配类型原文开篇就点明了 TypeScript 类型系统最重要的特征对象不必匹配一个具体的、精确的类型。只要一个对象满足了某个接口interface或类型type所要求的结构它就可以被用在需要该类型的地方即使两者之间没有任何显式的连接例如没有implements关键字。type NameProp1 { prop1: string; }; function log(x: NameProp1) { console.log(x.prop1); } const obj { prop2: 123, prop1: Origin, }; log(obj); // Valid这个例子浓缩了两个要点obj并没有声明: NameProp1注解但因为它拥有prop1: string这个成员所以可以被安全地传给logobj还额外拥有prop2属性这并不构成错误——结构化类型只要求目标类型成员齐全不要求完全相同。这正是结构化类型Structural Typing与名义类型Nominal Typing的本质区别类型兼容性由结构/形状决定而不是由类型名或声明位置决定。仓库中 exploring-the-type-system.md 明确写道TypeScript 是基于结构化类型系统的语言兼容性与等价性取决于类型实际的结构或定义而非像 C# 或 C 那样的名义类型系统取决于名字。二、结构化类型的判定规则至少要有相同成员TypeScript 的比较过程是递归的会作用于任意嵌套层级。其基础规则是类型 X 与 Y 兼容当且仅当 Y 至少拥有 X 的相同成员。type X { a: string; }; const y { a: A, b: B }; // Valid, as it has at least the same members as X const r: X y;y除了拥有a之外还多了b但根据结构化类型规则它仍然可以赋给X。这条规则贯穿于 TypeScript 的整个赋值检查参数按类型比较而非按名字比较函数返回类型必须兼容多余参数允许丢弃这与 JavaScript 中常见的Array.prototype.map()等回调用法如[1, 2, 3].map((element, _index, _array) ...)一致。详见 exploring-the-type-system.md。2.1 结构化类型与 JavaScript 鸭子类型结构化类型系统并非凭空设计它是受 JavaScript 运行时鸭子类型duck typing启发而来的运行时只要一个对象看起来像、叫起来像即拥有所需的方法与属性就能被当作目标使用。TypeScript 把这种动态行为前移到了编译期用静态结构检查来建模它。这一点在 exploring-the-type-system.md 的 Structural Typing 一节中有直接说明TypeScript 的结构化类型系统正是基于 JavaScript 动态鸭子类型在运行时的工作方式设计的。一个直观的例子是声明名不同的两个类型只要结构相同就互相兼容type X { a: string; }; type Y { a: string; }; const x: X { a: a }; const y: Y x; // Valid甚至两个类型可以在没有任何一方是另一方子类型的情况下互相重叠——因为 TypeScript 只看对象的形状interface X1 { a: string; } interface Y1 { a: string; b: string; } interface Z1 { a: string; b: string; c: string; } const z1: Z1 { a: a, b: b, c: c }; const r: Z1 z1; // Valid此处 z1 与 Z1 结构一致2.2 接口即契约无需显式 implements结构化类型的直接工程收益是接口可以作为一种隐式契约。当你定义函数参数为某个接口时任何调用方只要传入形状匹配的对象即可不需要被调用的类或对象显式声明implements。这与很多面向对象语言如 Java、C#中必须显式声明实现关系截然不同显著降低了模块之间的耦合也让测试替身mock/stub的编写变得非常自然——只要模拟出形状编译器就认可。关于接口的通用语法与type别名的写法对比可参见 interface-and-type.md关于接口与 type 在声明合并、扩展方式上的差异可参见 differences-between-type-and-interface.md。三、擦除的含义类型在编译期被完全移除Erased Structural Types中的 Erased擦除指的不是结构化判定被擦除而是类型本身在编译后被完全擦除。TypeScript 编译器有两大职责检查类型错误、编译成 JavaScript。这两个过程相互独立——类型不影响 JavaScript 运行时的执行因为它们会在编译期被完全擦除。例如下面这段带类型错误的代码const add (a: number, b: number): number a b; const result add(x, y); // Argument of type string is not assignable to parameter of type number.编译器仍然可以输出可执行的 JavaScriptuse strict; const add (a, b) a b; const result add(x, y); // xy由此可以推导出两个重要结论运行时无法检查 TypeScript 类型你不能在运行时用instanceof去判断一个接口类型因为接口在编译后不复存在。这也是 typescript-introduction.md 中反复强调的Dog only refers to a type, but is being used as a value here这类错误正是类型被擦除的直接体现。类型系统零运行时开销所有类型标注、接口、类型别名都在编译期消失不会产生任何性能负担只是引入一定的编译期开销。正因为类型会在运行时消失如果业务确实需要在运行时区分不同的类型就必须借助值层面的机制例如带标签的联合类型tagged union——用kind这样的字面量属性来标记对象interface Dog { kind: dog; // Tagged union bark: () void; } interface Cat { kind: cat; // Tagged union meow: () void; } type Animal Dog | Cat; const makeNoise (animal: Animal) { if (animal.kind dog) { animal.bark(); } else { animal.meow(); } };而真正的class因为同时存在于类型层面与值层面是少数可以用instanceof在运行时识别的对象。这套结构化判定 编译期擦除的组合正是 TypeScript 能同时做到静态检查严格与运行时与 JavaScript 完全一致的根本原因。四、结构化类型与余属性检查看似矛盾实则互补结构化类型允许形状超集的对象但 TypeScript 同时存在余属性检查Excess Property Checking它会在把对象字面量赋给变量或作为函数参数传入时检查对象是否含有目标类型未定义的属性。这两个机制并不矛盾type X { a: string; }; const y { a: a, b: b }; const x: X y; // Valid because structural typing const w: X { a: a, b: b }; // Invalid because excess property checking同样的{ a: a, b: b }经由变量y中转时合法结构化类型直接以字面量形式赋值时却报错余属性检查又称 freshness 检查。这可以理解为对象字面量被视为新鲜的编译器借此捕捉拼写错误或多余属性而一旦对象被赋值给变量完成拓宽freshness 就消失了只走纯粹的结构化兼容判定。与之相关的是弱类型Weak Types当某个类型只包含全部可选的属性时TypeScript 会把没有任何重叠的赋值视为错误type Options { a?: string; b?: string; }; const fn (options: Options) undefined; fn({ c: c }); // Invalid可通过类型断言fn({ c: c } as Options)或给弱类型添加[prop: string]: unknown索引签名来绕过。这些细节进一步说明结构化类型是主规则但 TypeScript 在其之上叠加了多个面向实战的检查避免结构化类型被滥用。完整示例见 exploring-the-type-system.md 的 Property Checking and Excess Property Checking、Weak Types 与 Strict Object Literal Checking (Freshness) 三节。五、结构化类型不是万能的需要名义语义的场景理解了结构化判定后也应了解它的边界类中的 private/protected 成员参与兼容性检查两个类即使公开结构完全相同只要一个拥有private成员另一个没有就无法互相赋值——private成员成为隐式的名义标签。枚举跨类型比较无效枚举值与 number 互相兼容但不同枚举类型之间的值不可直接比较。泛型按应用参数后的最终结构比较只有泛型参数实际进入最终结构时不同的类型实参才会导致不兼容。这些规则同样记录在 exploring-the-type-system.md 的 TypeScript Fundamental Comparison Rules 一节中。它们证明了TypeScript 虽然在对象形状层面坚持结构化但在类封装、枚举等语言特性上保留了必要的名义感防止结构相同的类被无差别混用。六、实践建议与总结综合原文档与仓库中的类型系统章节可以总结出几条实战原则把接口当作形状契约为函数参数定义最小的接口形状调用方只需结构满足即可无需显式implements这能大幅降低模块耦合。善用结构化类型但要留意字面量余属性检查对象字面量直接赋值或传参时会触发 freshness 检查优先通过先赋值给变量或类型声明的方式规避误报。记住类型会被擦除接口、类型别名、泛型等都不会出现在运行时需要运行时区分类型时用 tagged unionkind字段或classinstanceof而不是依赖类型名。在需要真正名义隔离时借助类的 private 成员或品牌brand技巧当两个结构相同但语义不同的类型不应互相赋值时结构化类型本身无能为力需要人为引入名义标记。Erased Structural Types 是 TypeScript 类型系统的基石用结构而非名字判定兼容用编译期擦除保证运行时纯净。它让 TypeScript 既贴近 JavaScript 的动态哲学又能提供静态安全保障。本文所有示例与规则均可在 erased-structural-types.md 及其姊妹篇 exploring-the-type-system.md、typescript-introduction.md 中进一步研读后者还涵盖了类型作为集合、类型推断、类型收窄narrowing等更多进阶主题可作为继续深入的方向。【免费下载链接】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创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

12kW全GaN AIDC电源:三电平架构与磁集成技术解析

12kW全GaN AIDC电源:三电平架构与磁集成技术解析

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

2026/9/24 15:23:38 阅读更多 →
PaddleHub 实战:使用 yolov3_darknet53_coco2017 模块完成 COCO2017 目标检测与在线服务部署

PaddleHub 实战:使用 yolov3_darknet53_coco2017 模块完成 COCO2017 目标检测与在线服务部署

人工智能大模型微调模型推理服务 【免费下载链接】PaddleFormers PaddleFormers is an easy-to-use library of pre-trained large language model zoo based on PaddlePaddle. 项目地址: https://gitcode.com/gh_mirrors/pa/PaddleFormers 点击查看 免费下载 导读…

2026/9/24 15:23:38 阅读更多 →
Salt msgpack 渲染器:面向数据型 Fileserver 后端的高数据序列化与反序列化指南

Salt msgpack 渲染器:面向数据型 Fileserver 后端的高数据序列化与反序列化指南

运维配置管理后端 【免费下载链接】salt Software to automate the management and configuration of infrastructure and applications at scale. 项目地址: https://gitcode.com/gh_mirrors/sa/salt 点击查看 免费下载 msgpack 渲染器(salt.renderers…

2026/9/24 15:22:38 阅读更多 →

最新新闻

真空喷涂机品牌推荐:从工艺流程到设备选型多维度完整分析

真空喷涂机品牌推荐:从工艺流程到设备选型多维度完整分析

在水产饲料和宠物食品加工中,油脂、诱食剂及部分热敏性营养组分通常需要在膨化和烘干后添加。真空喷涂机在不同真空度情况下,使脂肪或脂溶性的维生素等液体原料渗透到颗粒内部,提高液体添加比例,满足动物能量要求。布勒围绕水产饲…

2026/9/24 16:01:08 阅读更多 →
QuantsPlaybook:100+券商金工研报复现的完整指南,三步跑通你的第一个因子

QuantsPlaybook:100+券商金工研报复现的完整指南,三步跑通你的第一个因子

QuantsPlaybook:100券商金工研报复现的完整指南,三步跑通你的第一个因子 【免费下载链接】QuantsPlaybook 量化研究-券商金工研报复现 项目地址: https://gitcode.com/GitHub_Trending/qu/QuantsPlaybook QuantsPlaybook 是一个用 Python 复现 10…

2026/9/24 16:01:08 阅读更多 →
Dopamine BarPlotter 可视化指南:用 matplotlib + pygame 绘制强化学习 Agent 行为分布柱状图

Dopamine BarPlotter 可视化指南:用 matplotlib + pygame 绘制强化学习 Agent 行为分布柱状图

机器学习深度学习 【免费下载链接】dopamine Dopamine is a research framework for fast prototyping of reinforcement learning algorithms. 项目地址: https://gitcode.com/gh_mirrors/do/dopamine 点击查看 免费下载 导读 本文围绕 Dopamine 强化学习研究框…

2026/9/24 16:01:08 阅读更多 →
如何用SGLang部署openjev:外部模型包开发+吞吐提升1.5-3倍的完整部署指南

如何用SGLang部署openjev:外部模型包开发+吞吐提升1.5-3倍的完整部署指南

如何用SGLang部署openjev:外部模型包开发吞吐提升1.5-3倍的完整部署指南 【免费下载链接】openjev 项目地址: https://ai.gitcode.com/hf_mirrors/AlexWortega/openjev openjev 是一个基于 Qwen3.5 训练的 NLI 交叉编码器(jev 模型)&…

2026/9/24 16:01:08 阅读更多 →
RestSharp 错误处理完全指南:ResponseStatus 语义、异常抛出策略与实战排查

RestSharp 错误处理完全指南:ResponseStatus 语义、异常抛出策略与实战排查

后端API设计 【免费下载链接】RestSharp Simple REST and HTTP API Client for .NET 项目地址: https://gitcode.com/gh_mirrors/re/RestSharp 点击查看 免费下载 导读:本文以 RestSharp v112 官方错误处理文档为主体,结合仓库源码&#xff…

2026/9/24 16:01:08 阅读更多 →
上下文塞满后,AI 变傻又烧钱:5 个省 Token 的做法

上下文塞满后,AI 变傻又烧钱:5 个省 Token 的做法

先看一组实测数字。同一个"查 100 轮资料"的任务,不做处理时上下文峰值冲到 33.5 万 Token;把自动压缩的触发点设在 18 万之后,峰值降到 16.9 万,任务收尾时只剩 5829 个 Token,活照样干完了。这组轨迹来自 …

2026/9/24 16:00:08 阅读更多 →

日新闻

基于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 阅读更多 →