ARTICLE DETAIL

资讯详情

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

扩展类型:在 TypeScript 中组合与继承接口、类型与类

扩展类型:在 TypeScript 中组合与继承接口、类型与类 文档教程【免费下载链接】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 类型组合机制的关键一环它回答了如何基于已有类型派生新类型这一日常开发最高频的问题。读完本文你将掌握接口的extends继承、多重继承、类型别名的交叉类型以及接口可以扩展类型、类型不能反向扩展接口这一规则的深层原因并能区分扩展与声明合并这对容易混淆的概念。接口继承用 extends 复制另一个类型的成员在 TypeScript 中interface可以通过extends关键字从另一个接口复制全部成员。原文档给出的最小示例是interface X { a: string; } interface Y extends X { b: string; }这里Y不仅拥有自己声明的b: string还从X继承a: string。也就是说Y的最终形状等价于interface Y { a: string; b: string; }从结构化类型structural typing的角度看TypeScript 只关心形状是否满足约束任何同时包含a: string与b: string的对象都可以赋值给Y类型的变量。接口继承是纯类型层面的操作编译后不会产生任何运行时开销extends只存在于类型检查阶段。多重继承一次扩展多个接口interface支持从多个接口同时扩展用逗号分隔基接口列表。原文档示例interface A { a: string; } interface B { b: string; } interface Y extends A, B { y: string; }此时Y的成员是A、B与自身声明的并集即同时拥有a、b、y三个成员。这种多源继承非常适合把横切的能力拆成若干小接口再在业务接口上按需组合。注意与类的单继承限制不同类只能继承一个基类详见下文接口的多重继承是语言原生支持的。仓库中 合并与扩展章节 将这种机制概括为扩展extension指的是从已有类型或接口派生出新类型向现有类型追加属性或方法而无需修改原有定义。书中给出的完整示例interface Animal { name: string; eat(): void; } interface Bird extends Animal { sing(): void; } const dog: Bird { name: Bird 1, eat() { console.log(Eating); }, sing() { console.log(Singing); }, };注意这里赋给Bird类型变量的对象同时实现了name、eat与sing——这正是扩展后的完整约束。变量名dog虽与语义不符但不影响类型检查结构化类型只校验形状是否完备。extends 只适用于接口与类类型别名请使用交叉类型原文档强调了一个关键规则extends关键字只能用于interface和class对type别名组合多个类型要使用交叉类型运算符type A { a: number; }; type B { b: number; }; type C A B;C表示同时满足 A 与 B的类型其成员是a: number与b: number的并集。仓库的 交叉类型章节 给出了更完整的语义描述与验证示例type X { a: string; }; type Y { b: string; }; type J X Y; // 交叉类型 const j: J { a: a, b: b, };交叉类型是集合取交集的类型层面实现J类型的值必须同时具有X与Y的全部成员。相比interface extends交叉类型还能与联合类型、映射类型、条件类型等任意type表达式自由组合因此是类型别名场景下唯一的组合手段。在 接口与类型章节 中还演示了交叉类型与联合类型的组合使用type TypeA { name: string }; type TypeB { age: number }; type CombinedType TypeA TypeB; // 交叉类型 let myCombined: CombinedType { name: John, age: 25 };接口可以扩展类型但反过来不行原文档给出的最后一个语法形态是接口可以通过extends扩展一个type别名而type无法反向继承接口type A { a: string; }; interface B extends A { b: string; }也就是说interface B extends A是合法的——只要A是一个可解析的对象形状。而反过来type C ... extends B这种写法在 TypeScript 中根本不存在类型别名没有extends语法只能通过组合。为什么会有这种不对称从语言设计看extends的目标右侧必须是一个可以静态展开、成员完全确定的对象类型。interface和class天然满足这一要求而type别名可以是联合类型、条件类型、映射类型等复杂构造例如type Department dep-x | dep-y接口无法从联合类型继承成员接口与类型章节 明确提到an interface cannot extend a complex type like a union type。因此规则可以概括为右侧是可展开的对象形状接口、类或对象类型别名→ 左侧接口/类可用extends右侧是任意类型表达式 → 只能用交叉类型组合。若确实需要以接口参与联合类型接口与类型章节 提供了接口的联合写法interface A { x: x; } interface B { y: y; } type C A | B; // 接口的联合类型这里C是联合类型取值要么满足A含x: x要么满足B含y: y这是接口本身不具备、必须借助type别名才能表达的能力。同名成员冲突交叉类型与接口继承的行为差异扩展与交叉在同名属性上的处理并不相同这是一个容易踩坑的细节。交叉类型遇到同名但类型不兼容的成员时会产生never类型type A { value: string }; type B { value: number }; type C A B; // C 的 value 被推断为 string number即 never此时C实际上无法满足——不存在一个值同时是string又是number给C类型变量赋任何对象字面量都会报错。接口继承则不同同名成员要求类型互相兼容否则extends处直接报编译错误若兼容则允许覆盖。这种显式报错通常比交叉类型悄悄产生never更友好。这一差异也体现在 接口与类型章节 的对比示例中接口用extends继承并追加成员类型用合并成员两者的最终约束对象形状是一致的// 接口方式extends 继承 interface A { x: string; y: number; } interface B extends A { z: string; } // 类型方式交叉类型组合 type B2 A { j: string; };扩展与合并是两回事declaration merging在 TypeScript 术语里扩展extension与合并merging是两个不同的概念合并与扩展章节 对此做了清晰区分扩展从已有类型/接口派生新类型产生一个新的类型名字合并把同名的多个声明合并成一个定义不产生新名字。接口的声明合并declaration merging示例interface X { a: string; } interface X { b: number; } const person: X { a: a, b: 7, };两个X声明被合并为同时含a与b的单一接口。接口与类型章节 进一步指出只有接口支持声明合并type别名不支持。这在实际开发中的典型价值是可以在不修改第三方类型定义的前提下通过同名接口声明为其打补丁补充成员。需要注意的是声明合并与extends继承虽然都能让一个接口拥有更多成员但前者不改名、后者产生新类型名二者语义完全不同。类继承与接口实现extends 的另一个舞台extends也用于类继承。仓库 类章节 的继承Inheritance小节说明了类继承的机制子类继承基类的属性与方法并可添加新成员或覆写已有方法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!); } } const dog new Dog(Max, Labrador); dog.speak(); // Woof! Woof!与接口不同类只支持单继承class只能extends一个基类。当需要从多个来源获得行为与结构时TypeScript 的解法是让类implements多个接口interface Flyable { fly(): void; } interface Swimmable { swim(): void; } class FlyingFish implements Flyable, Swimmable { fly() { console.log(Flying...); } swim() { console.log(Swimming...); } }这条路径与本文主题一脉相承接口负责定义契约与结构extends/implements负责继承与实现type交叉类型负责任意形状组合三者共同构成 TypeScript 的类型扩展工具箱。实战建议何时用 extends、何时用 综合原文档与仓库相关章节可以给出如下选型建议场景推荐写法依据从多个接口派生新接口interface Y extends A, B接口天然支持多重继承给第三方接口补充成员不改名同名interface声明合并仅接口支持声明合并组合任意type表达式type C A Bextends不适用于类型别名对象类型别名之间组合type C A B类型别名无extends语法类的单继承class Dog extends Animal类只允许一个基类类实现多个契约class F implements A, B接口可被多实现需要强调的边界是interface extends的右侧必须是可静态展开的对象形状联合类型等复杂type无法被接口继承此时应改用交叉类型或接口的联合type C A | B。相关章节与进一步阅读扩展类型位于本书第 16 章侧边栏label: 16. Расширение типов英文原版为16. Extending Types。围绕本主题仓库还提供以下可继续深入阅读的章节交叉类型运算符的完整语义与示例接口与类型interface与type的公共语法、联合/交叉类型接口与类型的区别声明合并、扩展语法差异、联合与交叉的灵活性对比合并与扩展merging 与 extension 的概念辨析与完整代码类类继承、implements多接口实现第 55 章目录全书章节导航。本文内容同时存在于 俄语译本关联文档 与 英文原版 中两版示例完全一致可作为双语对照学习。原文档的全部示例单接口扩展、多接口扩展、类型交叉组合、接口扩展类型均已在上文完整保留并加以延伸可直接复制到tsc --strict环境下编译验证。赞分享文档教程【免费下载链接】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点击查看免费下载相关推荐LiteGraph.js与TypeScript接口继承类型扩展LiteGraph.js与TypeScript接口继承类型扩展 在使用LiteGraph.js进行节点图开发时TypeScript接口继承是扩展节点功能的关前端UI组件低代码TypeGraphQL 继承机制实战用 TypeScript 类继承组合 GraphQL 类型与 ResolverTypeGraphQL 继承机制实战用 TypeScript 类继承组合 GraphQL 类型与 Resolver TypeGraphQL 的核心设计理念是后端GraphQLAPI设计Bilibili-EvolvedTypeScript接口继承扩展现有类型Bilibili EvolvedTypeScript接口继承扩展现有类型 在Bilibili Evolved项目中TypeScript接口继承是构建灵活且可前端音视频上一篇spotify-player的开源社区行为准则营造友好环境下一篇WhiteRabbitNeo完全解析13B网络安全大模型如何打造攻防兼备的AI安全专家创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表