ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TypeScript 类型扩展(Extending Types)完全指南:`extends` 与 Intersection 的取舍

TypeScript 类型扩展(Extending Types)完全指南:`extends` 与 Intersection 的取舍 文档教程【免费下载链接】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 中扩展已有类型的两种核心手段——interface 的extends继承与 type 的交叉intersection并阐明它们各自的能力边界、适用场景与常见陷阱。读完本文你将掌握如何为接口多继承、如何用交叉类型组合对象类型以及为什么interface 可以扩展 type、反之则不行。一、什么是扩展类型在 TypeScript 的类型体系中扩展extend指的是从已有的类型复制成员并在此基础上追加新的成员从而得到一个新的、能力更完整的类型。它是构建可复用类型的基础操作与声明合并declaration merging是两个不同的概念扩展基于已有类型派生新类型继承其成员合并把多个同名声明合并成一个定义见 merging-and-extension.md。仓库文档用最简洁的示例说明了扩展的语义——复制一个类型的成员到另一个类型interface X { a: string; } interface Y extends X { b: string; }此时Y拥有a: string与b: string两个成员等价于直接书写interface Y { a: string; b: string; }这种复制成员的视角非常重要extends并不是运行时的原型继承那是 class 的事它只在类型层面上把父类型的结构复制进子类型。二、interface 的多继承一次扩展多个类型interface的extends子句支持逗号分隔多个父类型这一点与 class 的单继承限制不同TypeScript 的 class 只能继承一个基类但可以implements多个接口详见 class.md。接口层面天然支持多继承interface A { a: string; } interface B { b: string; } interface Y extends A, B { y: string; }最终Y的成员为a、b、y三个属性的并集。多继承常用于组合多个能力契约例如同时继承形状定义与颜色定义interface Size { width: number; height: number; } interface Color { color: string; } interface Rect extends Size, Color { label: string; }注意当多个父接口存在同名但类型不同的属性时TypeScript 会报错属性的类型必须兼容这一点与交叉类型的行为略有差异下文会展开。三、extends只适用于 interface 与 classtype 请用文档明确强调了一个关键边界extends关键字只对 interface 和 class 生效对 type 别名无效。若想扩展 type必须使用交叉类型操作符type A { a: number; }; type B { b: number; }; type C A B;C表示同时满足 A 与 B的类型其值必须同时拥有a与b两个属性。这与 intersection-types.md 中定义完全一致——交叉类型是表示一个值拥有两个或更多类型全部属性的类型type X { a: string; }; type Y { b: string; }; type J X Y; // Intersection const j: J { a: a, b: b, };3.1 为什么 type 不能使用extendstype 别名是类型的名称引用它本身没有继承这个语法位置type 的构造方式是运算符组合|联合、交叉、泛型等。文档在 differences-between-type-and-interface.md 中进一步补充了对比interface通过extends继承其他 interface语法直观、贴近面向对象思维type通过组合出交叉类型更接近集合运算的思维方式。interface A { x: string; y: number; } type B A { j: string; }; const c: B { x: x, y: 123, j: j, };上面的例子展示了混用先用 interface 定义A再用 type 的把它与一个匿名对象类型交叉得到B。3.2 交叉类型与属性冲突与 interfaceextends对同名属性要求类型必须兼容类似交叉类型在遇到同名属性时会做属性类型的交叉如果两个类型对同一属性给出不相容的类型例如string与number交叉结果会变成string number而这个类型没有值能同时满足实际退化为不可用的类型类似never。这是 type 扩展方式中需要特别留意的陷阱type A { id: string }; type B { id: number }; type C A B; // id 的类型是 string number几乎无法赋任何值因此在用组合类型时务必确保同名属性的类型相容。四、单向规则interface 可以扩展 type反之不行这是本主题中最反直觉的一条规则文档给出了明确的示例type A { a: string; }; interface B extends A { b: string; }允许interface B extends A中父类型A是 type 别名——interface 可以从 type 继承成员这是合法的。不允许反过来type 无法extendsinterface也没有类似语法type 只能通过把 interface 组合进来。也就是说扩展方向是单向的操作是否合法语法interface extends interface✅interface Y extends X {}interface extends class✅interface Y extends BaseClass {}继承实例成员的结构interface extends type✅interface B extends A {}A 为 typetype 扩展复制成员❌无extends语法type 组合✅type C A B;任意类型均可交叉为什么 type 可以作 interface 的父类型因为 interface 的extends只需父类型是一个具名类型type 别名完全满足该条件而 type 别名本质上是给类型表达式起名字语法层面没有设计继承位置所以只能靠运算符组合。这条规则的实践意义当你已经用 type 定义了领域模型又想在其上叠加契约式扩展时可以自然地把 type 作为 interface 的父类型反过来如果你的模型是从 interface 出发的则用把接口并入 type。五、扩展 vs 声明合并选择正确的手法文档所在章节的上文merging-and-extension.md专门区分了这两个概念扩展Extension——创建新类型复制并扩充已有类型的成员不修改原始定义interface Animal { name: string; eat(): void; } interface Bird extends Animal { sing(): void; }声明合并Merging——同名的多个 interface 自动合并为一个用于给已有类型打补丁或增量扩展interface X { a: string; } interface X { b: number; } const person: X { a: a, b: 7, };两者的差异总结维度扩展extends / 声明合并操作对象生成新的类型名同名 interface 合并成同一个类型修改原定义否是相当于补充原 interface支持者interface 与 type各自语法不同仅 interfacetype 不支持典型用途派生新类型、组合能力为已有接口增量添加成员、类型补丁关键约束见 differences-between-type-and-interface.mdtype 不支持声明合并。所以当你的需求是在不动原定义的前提下扩展类型用扩展当需求是给某个已有 interface 追加成员比如为库的类型打补丁只能用声明合并——此时父类型必须是 interface。六、与 class 的关联extends的另一种形态extends关键字同样作用于 class其语义是运行时原型继承 类型层面的成员继承详见 class.md。interface 的extends与 class 的extends共享同一个关键字但服务于不同抽象层次class Animal { name: string; constructor(name: string) { this.name name; } speak(): void { console.log(The animal makes a sound); } } class Dog extends Animal { breed: string; constructor(name: string, breed: string) { super(name); this.breed breed; } speak(): void { console.log(Woof! Woof!); } }TypeScript 的 class 不支持传统意义的多继承只能继承一个基类但可以通过implements多个 interface 来组合多个契约interface Flyable { fly(): void; } interface Swimmable { swim(): void; } class FlyingFish implements Flyable, Swimmable { fly() { console.log(Flying...); } swim() { console.log(Swimming...); } }这条规则反过来解释了 interface 与 class 的关系interface 是纯类型层面的继承class 是运行时的继承而两者都使用extends关键字。interface 还可以 extends class继承其实例成员的类型结构进一步印证interface 可以扩展任何具名类型的规则。七、实战决策清单综合本节文档与仓库相关章节当你需要扩展类型时可按下述流程决策起点是 interface想派生新接口→ 用extends可多继承interface Y extends A, B {}起点是 type或任意类型表达式想组合出新类型→ 用交叉type C A B;已有 type 模型想叠加接口契约→interface B extends A {}A 为 type合法已有 interface想扩展成 type→type T A {...};把 interface 并入交叉类型想给既有 interface 增量打补丁→ 依赖声明合并再次声明同名 interfacetype 无此能力组合中包含联合类型union→ 只能走 type 路线type C A | B;interface 没有内置联合语法详见 differences-between-type-and-interface.md。八、延伸阅读本章原始文档extending-types.md另有英文原版 extending-types.md交叉类型的完整定义intersection-types.mdinterface 与 type 的全面对比声明合并、扩展语法差异、联合/交叉能力differences-between-type-and-interface.md声明合并与扩展的概念辨析merging-and-extension.mdinterface / type 通用语法interface-and-type.mdclass 继承、多接口实现与extends的运行时语义class.md全书目录table-of-contents.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点击查看免费下载相关推荐TypeScript 类型扩展Extending Types完全指南interface 继承、多重扩展与交叉类型TypeScript 类型扩展Extending Types完全指南interface 继承、多重扩展与交叉类型 导读 在 TypeScript 的类型系文档教程The Concise TypeScript Book 系列TypeScript 类型扩展Extending Types全解析The Concise TypeScript Book 系列TypeScript 类型扩展Extending Types全解析 本文聚焦《The Conc文档教程TypeScript 交集类型Intersection Types完整指南用 组合多个类型TypeScript 交集类型Intersection Types完整指南用 组合多个类型 导读 交集类型Intersection Type是 T文档教程上一篇GeoLibre 桌面端完整安装指南Windows、macOS、Linux 一次装好这个开源 GIS下一篇5分钟搭起 HTTP 服务cpp-httplib单头文件、零依赖的 C 方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表