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),仅供参考
企业数字化 ERP 产品动态
相关推荐
MATLAB自适应啸叫抑制算法:LMS/NLMS/VMLMS仿真与评价 /* 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:13
Arduino UNO驱动42步进电机:闭环控制告别丢步,精准调速实战 /* 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:13
STM32无DAC怎么办?用PWM+RC滤波实现高精度模拟电压输出 /* 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:00
LX Music 桌面版免费多源音乐搜索下载完整指南 LX Music 桌面版免费多源音乐搜索下载完整指南 【免费下载链接】lx-music-desktop 一个基于 Electron 的音乐软件 项目地址: https://gitcode.com/GitHub_Trending/lx/lx-music-desktop
凌晨一点,想找一首歌的完整版,你翻遍了三个音乐 App&#x… · 2026/9/24 15:56:46
Docker之镜像、容器、数据卷关系 Docker之镜像、容器、数据卷关系一个 Image(镜像)可以创建多个 Container(容器);Container 挂载 Volume(数据卷)后,数据可以在删除旧容器、创建新容器后继续使用。概念含义类比Image… · 2026/9/24 15:56:39
基于图像识别的跨平台 UI 自动化框架:Airtest 安装、Python API 与 CLI 实战指南 测试质量保障计算机视觉 【免费下载链接】Airtest UI Automation Framework for Games and Apps 项目地址: https://gitcode.com/gh_mirrors/ai/Airtest 点击查看 免费下载 Airtest 是网易开源的跨平台 UI 自动化框架,专为游戏和 App 设计,核… · 2026/9/24 15:56:33
Perfetto heapprofd 完全指南:如何从火焰图到 SQL 查清堆内存的每一分去向 Perfetto heapprofd 完全指南:如何从火焰图到 SQL 查清堆内存的每一分去向 【免费下载链接】perfetto Production-grade client-side tracing, profiling, and analysis for complex software systems. 项目地址: https://gitcode.com/GitHub_Trending/pe/perfett… · 2026/9/24 15:56:27
基于vue的蛋糕定制预约自提系统[Vue]-计算机毕业设计源码+LW文档 摘要:随着消费者对个性化蛋糕需求的增长以及线上消费习惯的普及,开发一个高效便捷的蛋糕定制预约自提系统具有重要的现实意义。本文阐述了一个基于Vue框架开发的此类系统,详细介绍了其从需求分析到设计、实现的全过程。系统实现了用户蛋糕定… · 2026/9/24 15:56:27
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44