TypeSpec 语言基础:Union 联合类型完全指南(表达式、具名联合与 extends 约束)
TypeSpec 语言基础Union 联合类型完全指南表达式、具名联合与 extends 约束【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec本文是 TypeSpec 语言基础系列中关于 Union联合类型的完整技术指南。Union 定义了一个类型必须恰好是若干候选变体variant中的一种TypeSpec 同时提供「联合表达式」union expression与「具名联合」named union两种声明形式并通过实验性的extends约束为多态建模提供编译期保障。读完本文你将掌握|运算符的用法、union关键字的具名声明、extends基类约束的启用与校验规则以及union关键字在表达式位置的实验特性并了解编译器在 checker.ts 中的底层校验实现。联合类型概述在 TypeSpec 中Union 描述的是一个必须恰好等于多个可能变体之一的类型。与交集类型intersection表示同时满足不同联合类型表达的是多选一的关系这与大多数编程语言中的sum type / tagged union概念一致。TypeSpec 提供两种联合类型声明方式联合表达式Union expressions未命名直接用|运算符组合各变体具名联合Named unions用union关键字声明可为联合本身及每个选项命名。两种形式在语义上等价但具名联合能为发射器emitter提供更丰富的结构化信息这一点将在下文展开。Union 表达式用|组合变体未命名的联合类型即联合表达式通过|运算符把多个变体拼合而成通常配合alias使用alias Breed Beagle | GermanShepherd | GoldenRetriever;在上面的例子中Breed可以是Beagle、GermanShepherd或GoldenRetriever三者之一。|运算符可以连接模型、标量scalar、枚举、字符串/数字字面量等任意类型表达式是快速内联表达或关系的最直接手段。具名联合union 关键字与具名变体具名联合允许为联合赋予名称并为每个变体提供显式的命名引用。在概念上具名联合与 枚举enums 有些相似但区别在于枚举的成员是string或numeric值而联合的变体是 记录模型record models。具名联合使用union关键字声明其名称必须是一个合法的identifierunion Breed { beagle: Beagle, shepherd: GermanShepherd, retriever: GoldenRetriever, }这个例子与前面用alias定义的Breed完全等价差异在于发射器可以把Breed识别为一个具名实体named entity并识别出beagle、shepherd、retriever这些选项的名称从而生成更友好的代码例如生成带标签的联合、判别联合或带枚举名的映射这种格式还允许对每个选项单独应用 装饰器decorators。从编译器内部看每个变体会被建模为独立的UnionVariant对象携带name、type和所属union引用见 types.ts。变体在源码中出现的顺序会被保留在variants映射中作为联合选项的稳定顺序。用 extends 约束联合实验特性启用方式与声明语法具名联合可以通过extends关键字声明一个基类型base type。联合中的每一个变体都必须可赋值assignable给该基类型否则编译器会在违规的变体上报告诊断错误。:::caution Union 的extends子句是实验特性需要显式启用union-extends编译器特性。在tspconfig.yaml中启用features: - union-extends:::启用后即可书写如下代码model Dog { name: string; } model Beagle extends Dog { huntingSkill: string; } model GermanShepherd extends Dog { guardingSkill: string; } union Breed extends Dog { beagle: Beagle, shepherd: GermanShepherd, }extends 的两大用途该约束服务于两个明确目的防止一类常见错误杜绝把不相关的类型误加入联合。例如在Breed extends Dog下若误写union Breed { beagle: Beagle, cat: Cat }编译器会立即在cat: Cat上报告可赋值性诊断在类型图中记录公共基类型extends声明的基类型会被记录在联合的baseType字段中发射器可以据此在原生不支持联合的语言中用多态基类型polymorphic base type来表达这个联合。需要特别强调的是基类型不会成为联合的一个变体。上面的Breed仍然恰好只有两个变体beagle与shepherdDog本身并不属于联合的取值集合。extends 是约束不是继承声明extends是可赋值性约束而非继承关系的声明。变体只需要可赋值给基类型即可不要求显式 extends 该基类型model Dog { name: string; } model Beagle { name: string; huntingSkill: string; } // Ok: Beagle 可赋值给 Dog即使它没有显式 extends Dog union Breed extends Dog { beagle: Beagle, }基表达式的合法类型extends的基表达式必须解析为以下四类类型之一model模型scalar标量enum枚举union联合这包括能够解析为上述数据类型的联合表达式、交集表达式、数组表达式和模板表达式。匿名模型表达式anonymous model expressions不能直接使用也不能通过 alias 间接使用。union OperationStatus extends string { Running, Succeeded, Failed, }上面这个例子展示了extends string的用法基类型是内建标量string各变体为字符串字面量。编译器源码 checker.ts 中的isUnionBaseType函数正是按Model | Scalar | Enum | Union四种类型进行判定同时 checker.ts 会专门拦截基类型为ModelExpression匿名模型表达式的情况并报告 Unions cannot extend model expressions. 诊断。extends 不等于可扩展:::cautionextends并不表示该联合是可扩展的extensible。union Foo extends string { a, b }与union Foo { a, b }描述的是完全相同的取值集合发射器应当对二者一视同仁。若希望允许额外的值需要显式地为它们添加一个变体union OperationStatus extends string { Running, Succeeded, Failed, string, // 显式允许其他任意字符串 }:::与 discriminator 的交互extends与discriminator装饰器没有任何交互。discriminator(kind)用于在模型属性上声明判别属性详见 built-in-decorators.md 中discriminator一节而extends只负责可赋值性约束与类型图记录两者职责互不重叠。编译器实现对此有明确注释baseType只是约束的记录——它不暗示子类化关系、不意味着联合可扩展、也与discriminator无交互并且发射器不应强制要求该字段存在拥有相同变体但无extends子句的联合应被同样处理见 types.ts。底层校验机制源码级在编译器 checker.ts 中checkUnion函数按以下顺序处理具名联合特性门控若联合带extends子句且未启用union-extends特性报告union-extends-disabled诊断checker.ts构建类型创建Union类型对象并依据节点是否为UnionDeclarationExpression设置expression标志解析基类型调用checkUnionBaseType解析extends表达式包括循环基类型检测circular-base-type与匿名模型表达式拦截校验变体checkUnionVariants遍历各变体检测重名变体union-duplicate诊断见 messages.ts 中的union-duplicate并对每个变体调用checkUnionVariantAgainstBaseType执行可赋值性检查注册命名空间非表达式形式的具名联合会被注册到所属命名空间namespace.unions.set(...)而表达式形式的联合不会注册。特性本身在 features.ts 中注册描述为 Enables experimental unionextendsclauses in project code.。isCompilerFeatureEnabledfeatures.ts会从拥有该源文件的包project 或 library的tspconfig.yaml中解析特性列表这意味着库可以在自己的配置中为自身代码启用该特性而无需影响使用方项目。此外模板化的联合带模板参数的union FooT extends ...在校验时会跳过未实例化模板声明中的变体验证改为在每次实例化时校验相关场景在 union.test.ts 中有大量测试覆盖包括union a extends a { x: string }自引用循环检测等。表达式位置的关键字联合实验特性:::warning 声明表达式declaration expressions是 TypeSpec 的实验特性默认关闭。除非在tspconfig.yaml的features列表中加入declaration-expressions否则在表达式位置使用model、enum、union或scalar声明都会被判定为错误kind: project features: - declaration-expressions:::启用后union关键字可以出现在任何期望类型表达式的位置——例如作为 alias 的值、属性的类型、装饰器或模板参数、元组元素等。与|运算符构建的联合表达式不同关键字形式可以携带名称和具名变体model Pet { // 表达式位置上的匿名关键字联合 breed: union { Beagle, GermanShepherd, }; // 表达式位置上的具名关键字联合 size: union Size { small: S, medium: M, large: L, }; }该特性在 features.ts 中注册描述为允许在表达式位置使用具名或匿名的 model、scalar、enum 和 union 声明。不注册命名空间、不参与扁平化关于表达式位置的关键字联合有三个容易被忽略的语义细节不注册到命名空间表达式位置的关键字联合会被标记为表达式即使赋予了名称也不会注册到所在命名空间。名称仅保留在结果类型上用于显示目的——无法在其他地方引用它不参与扁平化与|运算符不同作为操作数使用的关键字联合不会被扁平化进周围的联合。例如union { a, b } | c产生的是嵌套的union { a, b }与c的联合内层的具名变体被保留下来。这一点与普通联合表达式会被合并进外层联合的行为有本质区别同样支持 extends 约束表达式位置的联合也可以用extends约束其变体model Pet { breed: union extends Dog { Beagle, GermanShepherd, }; }此外表达式位置的关键字联合可以内联应用装饰器和文档注释并且可以通过导航引用navigation reference如::type对其进行增补augment。由于关键字联合与具名联合共用同一套checkUnion校验逻辑上述extends约束、特性门控与变体验证规则在表达式位置同样生效。小结与推荐阅读本文完整覆盖了 TypeSpec Union 的三种形态联合表达式|运算符轻量、内联适合快速表达多选一具名联合union关键字为联合与各变体命名供发射器生成更结构化、更友好的输出并支持逐变体应用装饰器extends 约束实验特性编译期强制所有变体可赋值给基类型防止无关类型混入并在类型图中记录公共基类型以支持多态表达基类型不会成为变体、不意味着可扩展、与discriminator无交互表达式位置的关键字联合declaration-expressions实验特性把联合直接嵌入属性、参数等类型表达式位置携带名称但不注册命名空间、不参与外层扁平化。相关源码与测试可继续深入编译器校验逻辑checker.tsUnion 类型定义与baseType语义types.ts实验特性注册与启用解析features.ts诊断消息定义messages.tsextends 约束与循环检测测试union.test.ts声明表达式特性测试declaration-expressions.test.ts建议继续阅读语言基础系列的 模型models、枚举enums 与 类型关系type-relations以理解本文中可赋值性与模型声明背后的完整类型系统装饰器机制可参考 decorators.md。【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Android Studio No Module报错排查指南:从Gradle同步到缓存清理

Android Studio No Module报错排查指南:从Gradle同步到缓存清理

先给你还原一个我见过无数遍的场景:你把刚拉下来的项目往 Android Studio 里一拖,右上角那个绿色的 Run 按钮是灰的,点开运行配置,弹出一个让人血压升高的提示——No Module。更气人的是,代码看起来没问题,…

2026/9/19 0:35:53 阅读更多 →
Technology Stack  Versions

Technology Stack Versions

Technology Stack & Versions 【免费下载链接】BMAD-METHOD Breakthrough Method for Agile Ai Driven Development 项目地址: https://gitcode.com/gh_mirrors/bm/BMAD-METHOD Node.js 20.x, TypeScript 5.3, React 18.2State: Zustand (not Redux)Testing: Vitest…

2026/9/19 0:35:53 阅读更多 →
Jupyter Notebook网页打不开?端口、localhost与内核排查

Jupyter Notebook网页打不开?端口、localhost与内核排查

深夜十一点半,你敲下jupyter notebook,终端很快吐出一行地址:http://localhost:8888/tree?token...,然后光标一闪一闪地停在那儿。你等着浏览器自己蹦出来,等了十秒,屏幕纹丝不动;手动把地址粘…

2026/9/19 0:35:53 阅读更多 →

最新新闻

Omost 图像生成工作流完整拆解:LLM 如何用 Canvas 代码构图

Omost 图像生成工作流完整拆解:LLM 如何用 Canvas 代码构图

Omost 图像生成工作流完整拆解:LLM 如何用 Canvas 代码构图 【免费下载链接】Omost Your image is almost there! 项目地址: https://gitcode.com/GitHub_Trending/om/Omost Omost 把 LLM 的"写代码"能力换成了可渲染的图像合成产物:模…

2026/9/20 2:59:09 阅读更多 →
AssetRipper 完整教程:三步把游戏文件还原成可编辑的 Unity 项目

AssetRipper 完整教程:三步把游戏文件还原成可编辑的 Unity 项目

AssetRipper 完整教程:三步把游戏文件还原成可编辑的 Unity 项目 【免费下载链接】AssetRipper GUI application to analyze game files 项目地址: https://gitcode.com/GitHub_Trending/as/AssetRipper AssetRipper 是一款免费开源的 Unity 资产提取与分析工…

2026/9/20 2:59:09 阅读更多 →
ESP32-P4 USB Host鼠标实战:裸机HID协议解析与工业级应用

ESP32-P4 USB Host鼠标实战:裸机HID协议解析与工业级应用

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

2026/9/20 2:59:09 阅读更多 →
Pylint和Flake8:Python代码质量双卫士的配置与实践

Pylint和Flake8:Python代码质量双卫士的配置与实践

代码写出来首先是给人看的,顺便才是给机器执行。这句话在 Python 社区流传很广,我用了几年 Python 之后愈发觉得,相比机器能不能跑通,更关键的往往是“别人能不能看懂”。但人的审美千差万别,有人喜欢列表推导式层层嵌…

2026/9/20 2:59:09 阅读更多 →
基于STM32与RFID的智能停车收费系统设计与实现

基于STM32与RFID的智能停车收费系统设计与实现

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

2026/9/20 2:59:09 阅读更多 →
电动汽车驱动系统EMC复测整改:从干扰机理到工程实践

电动汽车驱动系统EMC复测整改:从干扰机理到工程实践

简介:电动汽车驱动系统因引入大功率、大电流电力电子部件,成为整车电磁兼容问题的关键来源,这份PDF即围绕该命题展开。资源是一篇来自上海大学的期刊论文,面向新能源汽车研发、测试及电磁兼容整改工程师,以实车运行中的…

2026/9/20 2:58:08 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →