The Concise TypeScript Book 精读:判别式联合(Discriminated Unions)实战指南

发布时间:2026/9/25 4:57:46

The Concise TypeScript Book 精读:判别式联合(Discriminated Unions)实战指南 文档教程【免费下载链接】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点击查看免费下载判别式联合Discriminated Unions又称可辨识联合是 TypeScript 类型系统中最实用的模式之一它通过一个公共的判别属性discriminant让编译器能在运行时分支中精确收窄联合成员的类型。本文以开源项目The Concise TypeScript Book的 discriminated-unions 章节本仓库同时提供 英文原文为骨架结合仓库中 Narrowing、Control Flow Analysis、Exhaustiveness Checking 与 Never type 等相邻章节深入讲解判别式联合的定义、核心示例、底层收窄原理与穷尽性检查实践。读完本文你将能熟练用判别式联合建模同一事物的多种形态写出类型安全、可穷尽检查、易于维护的 TypeScript 代码。一、什么是判别式联合TypeScript 中的判别式联合是一种特殊的union type联合类型它使用一个公共属性——即判别属性discriminant——来收窄narrow down联合中可能的类型集合。先回顾普通联合类型正如 Union Type 章节 所讲联合类型表示一个值可以是若干类型之一用|符号连接每种可能的类型let x: string | number; x hello; // Valid x 123; // Valid普通联合类型在编译期虽然知道可能是 string 或 number但如果不做显式判断编译器并不知道当前x具体是哪一种。判别式联合正是在此基础上加上了可以精确区分成员的机制每个联合成员都是一个对象类型或 interface每个成员都包含同一个属性即判别属性该属性的类型必须是字面量类型如square、circle或枚举等可区分值每个成员的判别属性取值互不相同形成一一对应的指纹。这样编译器只需检查这个公共属性的值就能在控制流中确定对象具体属于哪个成员并自动收窄出该成员独有的属性。二、核心示例用kind判别 Square 与 Circle原文档给出了一个完整、可运行的经典示例——用判别式联合建模形状并用switch计算面积。下面逐段解读。定义判别式联合类型type Square { kind: square; // Discriminant size: number; }; type Circle { kind: circle; // Discriminant radius: number; }; type Shape Square | Circle;要点说明kind就是判别属性discriminant注释已明确标出Square.kind的字面量类型是squareCircle.kind是circle两者取值唯一且互斥Shape Square | Circle构成判别式联合kind是该联合的公共可判别键。用 switch 按判别属性收窄const area (shape: Shape) { switch (shape.kind) { case square: return Math.pow(shape.size, 2); case circle: return Math.PI * Math.pow(shape.radius, 2); } };这段代码的精髓在于当switch检查shape.kind square时TypeScript 的控制流分析会把shape收窄为Square因此在case square分支内可以安全访问shape.size同理在case circle分支内shape被收窄为Circle可以访问shape.radius。如果试图在某个分支访问不属于该成员类型的属性编译器会直接报错。实例化并验证输出const square: Square { kind: square, size: 5 }; const circle: Circle { kind: circle, radius: 2 }; console.log(area(square)); // 25 console.log(area(circle)); // 12.566370614359172运行结果验证area(square)Math.pow(5, 2) 25area(circle)Math.PI * Math.pow(2, 2)≈ 3.14159 × 4 ≈ 12.566370614359172。注意由于area的两个case分支都返回了值且Shape恰好只有两个成员TypeScript 能判定该函数在所有输入下都有返回值这同样是收窄分析的功劳。三、判别式联合如何与类型收窄协同工作判别式联合之所以开箱即用底层依赖 TypeScript 的类型收窄Narrowing能力。如 Narrowing 章节 所述narrowing 是在条件块内精化变量类型的过程在处理联合类型变量可能具有多种类型时非常有用。除了判别式联合依托的switch等值判断外TypeScript 还识别多种收窄方式它们可以按需组合typeof 类型守卫typeof type guards基于变量的内置 JavaScript 类型进行检查const fn (x: number | string) { if (typeof x number) { return x 1; // x is number } return -1; };真值收窄Truthiness narrowing通过变量是否为真值来收窄类型const toUpperCase (name: string | null) { if (name) { return name.toUpperCase(); } else { return null; } };等值收窄Equality narrowing通过与特定值比较来收窄类型常与switch及、!、、!等操作符配合使用——判别式联合正是这种方式的典型应用const checkStatus (status: success | error) { switch (status) { case success: return true; case error: return null; } };in 操作符收窄In operator narrowing基于属性是否存在来收窄类型适合判别属性为布尔/可选、难以用字面量区分的场景type Dog { name: string; breed: string; }; type Cat { name: string; likesCream: boolean; }; const getAnimalType (pet: Dog | Cat) { if (breed in pet) { return dog; } else { return cat; } };instanceof 收窄基于构造函数检查对象实例class Square { constructor(public width: number) {} } class Rectangle { constructor( public width: number, public height: number ) {} } function area(shape: Square | Rectangle) { if (shape instanceof Square) { return shape.width * shape.width; } else { return shape.width * shape.height; } } const square new Square(5); const rectangle new Rectangle(5, 10); console.log(area(square)); // 25 console.log(area(rectangle)); // 50判别式联合相对于in、instanceof等方案的优势在于判别属性是联合成员上显式声明、字面量可枚举的键编译器能据此做最精确、可穷尽的分析且在数据跨边界传递如 API 响应时无需运行时类型库即可安全判别。四、控制流分析判别式联合收窄的底层原理判别式联合的收窄由 TypeScript 的**控制流分析Control Flow Analysis**驱动。根据 Control Flow Analysis 章节控制流分析会静态分析代码执行流以推断变量类型并基于分析结果对变量类型进行必要收窄。该章节还指出了两个重要的能力边界直接关系到判别式联合的写法1. 通过 const 变量间接引用判别属性也可以收窄。在 TypeScript 4.4 之前代码流分析只作用于if语句内部从 TypeScript 4.4 起它也能作用于条件表达式以及通过 const 变量间接引用的判别属性访问。例如const f1 (x: unknown) { const isString typeof x string; if (isString) { x.length; } }; const f2 ( obj: { kind: foo; foo: string } | { kind: bar; bar: number } ) { const isFoo obj.kind foo; if (isFoo) { obj.foo; } else { obj.bar; } };在f2中把判别比较结果存入const isFoo后续if (isFoo)仍能正确收窄obj.kind对应的成员并访问obj.foo/obj.bar。这正是 4.4 版本带来的判别属性间接引用分析。2. 某些写法会破坏收窄。该章节也给出了收窄不发生的反例若比较结果存入非 const 变量或在函数体内对obj重新赋值收窄都会失效const f1 (x: unknown) { let isString typeof x string; if (isString) { x.length; // Error, no narrowing because isString it is not const } }; const f6 ( obj: { kind: foo; foo: string } | { kind: bar; bar: number } ) { const isFoo obj.kind foo; obj obj; if (isFoo) { obj.foo; // Error, no narrowing because obj is assigned in function body } };另外该章节注明条件表达式中最多分析五层间接引用up to five levels of indirection。因此在书写判别式联合时建议让判别比较尽量直接、扁平避免过度嵌套的间接引用。五、穷尽性检查用never兜住所有分支判别式联合的一大价值在于它天然支持穷尽性检查Exhaustiveness Checking。如 Exhaustiveness Checking 章节 所述穷尽性检查能确保判别式联合的所有可能情况都在switch或if中被处理。never 类型回顾never表示永远不会发生的值。根据 Never type 章节它常用于标注永不返回的函数或表达式例如无限循环与抛错const infiniteLoop (): never { while (true) { // do something } }; const throwError (message: string): never { throw new Error(message); };用 never 构建穷尽性检查在switch的default分支中将收窄后的变量赋给一个never类型变量。如果联合中出现了未被case处理的成员该成员的判别值类型不是never赋值就会产生编译错误——从而在编译期阻止新增类型却忘记处理的回归type Direction up | down; const move (direction: Direction) { switch (direction) { case up: console.log(Moving up); break; case down: console.log(Moving down); break; default: const exhaustiveCheck: never direction; console.log(exhaustiveCheck); // This line will never be executed } };never类型的用途就是确保 default 分支是穷尽的一旦有人往Direction增加新值例如left而没有在switch中处理TypeScript 就会在const exhaustiveCheck: never direction;处报错。更常见的实战写法是在 default 分支抛错让未穷尽在运行时也显式暴露type Direction up | down; const move (direction: Direction): void { switch (direction) { case up: // move up break; case down: // move down break; default: const exhaustiveCheck: never direction; throw new Error(Unhandled direction: ${exhaustiveCheck}); } };把这条实践与本文第二节的面积示例结合就得到判别式联合的完整最佳实践模板字面量判别属性 → switch 收窄各成员 → default 分支做 never 穷尽检查。六、实践要点与相关章节导航综合原文档与仓库相邻章节使用判别式联合时可遵循以下要点判别属性选型使用字符串/数字字面量类型或as const修饰的对象、枚举保证每个成员取值唯一且可枚举分支收窄优先用switch (x.discriminant)编译器会为每个case精确收窄成员类型间接引用若要先把判别比较结果存入变量务必使用const且注意最多五层间接引用的分析边界见 Control Flow Analysis穷尽兜底始终在default分支使用never赋值可配合抛错把遗漏分支变成编译错误适用场景API 响应判别如{ status: ok, data } | { status: error, message }、Redux/状态机 action 建模、UI 组件多形态渲染等。The Concise TypeScript Book 在 目录章节 中将判别式联合编排在探索类型系统 / 类型收窄一节的末尾紧随 Narrowing 与 Analisis Alur Kontrol其后紧跟 Tipe never 与 Pemeriksaan Kelengkapan。建议按联合类型 → 收窄 → 控制流分析 → 判别式联合 → never → 穷尽性检查的顺序连续阅读即可完整掌握这一模式的全部原理与工程实践。赞分享文档教程【免费下载链接】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 精读Discriminated Unions可判别联合实战指南The Concise TypeScript Book 精读Discriminated Unions可判别联合实战指南 判别联合Discriminate文档教程The Concise TypeScript Book 精读Discriminated Unions 判别联合类型完全指南The Concise TypeScript Book 精读Discriminated Unions 判别联合类型完全指南 判别联合Discriminate文档教程The Concise TypeScript Book 精讲判别联合Discriminated Unions的类型收窄实战The Concise TypeScript Book 精讲判别联合Discriminated Unions的类型收窄实战 本篇为开源仓库 The Con文档教程上一篇7个实用技巧open-notebook故障注入测试实践指南提升系统可靠性的终极方法下一篇SWE-bench测试结果可视化直观展示评估数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/25 4:57:46

I2C通信协议深度解析:开漏输出、时序与多主仲裁实战

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

2026/9/25 7:12:50

ApiGo平台MCP接入AI办公:TaoToken统一Key配置与REST API联调大纲

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

2026/9/25 7:12:50

C#上位机温室监控系统:串口Modbus通信与数据联动实战

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

2026/9/25 7:12:50

第060篇 拿下Shopee工程化Offer:前端构建体积优化有哪些手段,Tree Shaking 如何生效|避坑指南

摘要:本篇复盘 Shopee 前端开发岗位在 工程化 方向的真实问法,重点拆 8 道题:前端构建体积优化有哪些手段,Tree Shaking 如何生效、依赖注入解决了什么问题,和工厂有何不同、ES Module 与 CommonJS 的区别,模块打包原理。每题按「考察点 → 参考答案 → 代码/实操 → 易…

2026/9/25 7:12:50

第059篇 工程化面试通关:B站如何考Monorepo 方案怎么选,pnpm workspace…

摘要:本篇复盘 B站 前端开发岗位在 工程化 方向的真实问法,重点拆 8 道题:前端工程的 CI/CD 应如何落地、怎么推动一项没人愿意做的技术改进、Webpack 与 Vite 的核心差异,各自适用场景。每题按「考察点 → 参考答案 → 代码/实操 → 易错点 → 面试官追问」五段式展开,既…

2026/9/25 7:07:50

Aviator表达式引擎语法手册:从基础到高级实践

/* 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 20:24:47

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/25 0:02:35

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:02:35

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:02:35

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑