news 2026/9/26 2:58:10

The Concise TypeScript Book:深入解析 TypeScript 字面量类型(Literal Types)——从单元素集合到可辨识联合

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
The Concise TypeScript Book:深入解析 TypeScript 字面量类型(Literal Types)——从单元素集合到可辨识联合
  • 文档
  • 教程

【免费下载链接】typescript-book

The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.

项目地址:https://gitcode.com/gh_mirrors/typ/typescript-book
点击查看免费下载

字面量类型(Literal Types)是 TypeScript 类型系统中"最精确"的一类类型:它把某个具体的 JavaScript 原始值(一个字符串、一个数字或一个布尔值)本身上升为一种类型。本篇指南以 The Concise TypeScript Book 意大利语版的 Tipi letterali 章节为主体,结合仓库中 字面量推断、联合类型、类型收窄、可辨识联合、穷尽性检查、模板联合类型 与 类型系统探索 等章节深入展开。读完你将掌握字面量类型的定义、推断规则,以及如何用它构建类型安全的联合类型、可辨识联合、穷尽性检查等实战模式。

什么是字面量类型:类型即集合视角下的"单元素集合"

在 The Concise TypeScript Book 中,字面量类型的定义非常精炼:

一个字面量类型是集合类型(collective type)内部的单元素集合(single-element set);它定义了一个非常精确的值,而这个值就是一个 JavaScript 原始值。

这句话背后是 TypeScript 的"类型即集合"思想。仓库的 Esplorazione del sistema di tipi 章节中明确写道:"在 TypeScript 中,一个类型是可能值的集合,该集合也被称为类型的域(domain)。类型中的每个值都可以看作集合中的一个元素。"该章节还给出了一张集合论术语与 TypeScript 类型的对照表:

集合术语TypeScript说明
空集nevernever中不包含任何值
单元素集合undefined/null/字面量类型恰好只有一个值
有限集合boolean/ 联合类型有限个值
无限集合string/number/object无穷多个值
全集any/unknown每个元素都是any的成员

由此可见:string是"所有字符串组成的无限集合",而'a'(字面量类型)是"恰好只有'a'这一个字符串的单元素集合"。字面量类型把类型从"宽泛的分类"收敛到"精确的常量",这正是它被用于约束取值范围的根基。

三种字面量类型:字符串、数字、布尔

TypeScript 中的字面量类型只有三类,全部对应 JavaScript 原始值:

  • 字符串字面量类型(String Literal Types):如'a'
  • 数字字面量类型(Numeric Literal Types):如1
  • 布尔字面量类型(Boolean Literal Types):如true

原文档给出的基础示例:

const a = 'a'; // 字符串字面量类型 const b = 1; // 数字字面量类型 const c = true; // 布尔字面量类型

注意:上例中三个变量都用const声明,因此它们的类型会被推断为精确的字面量类型'a'、1、true,而不是宽泛的string、number、boolean。这正是下一节"字面量推断"要讲的核心规则。

字面量推断:为什么const与let推断结果不同

字面量类型与类型推断(Inference)紧密相关。仓库的 Inferenza letterale 章节解释了 TypeScript 的关键推断行为:

字面量推断(Literal Inference)是 TypeScript 的一项特性,它允许根据变量的值推断出变量的类型。

const x = 'x'; // 字面量类型 'x',因为这个值此后无法改变 let y = 'y'; // 类型 string,因为我们可以随时修改这个值

推断规则:const声明的变量不可重新赋值,所以 TypeScript 敢于把类型收窄为精确的字面量类型;而let声明的变量随时可被改成其他字符串,所以会被拓宽(widening)为string。

一个更隐蔽的陷阱出现在对象属性上:即使属性值看起来是字面量,TypeScript 默认也认为它可以被后续修改,因此推断为宽泛类型:

type X = 'a' | 'b'; let o = { x: 'a', // 这是宽泛的 string,而不是字面量 'a' }; const fn = (x: X) => `${x}-foo`; console.log(fn(o.x)); // 报错:类型 'string' 不能赋给参数类型 'X'

由于o.x被推断为string(而非字面量'a'),把它传给只接受X的函数时 TypeScript 会报错——X是比string更窄(narrower)的类型。解决方式有两种,都是类型断言(type assertion):

let o = { x: 'a' as const, // 断言为字面量 'a' };
let o = { x: 'a' as X, // 断言为联合类型成员 'a' };

除了as const与as X这类局部断言,仓库 Esplorazione del sistema di tipi 章节还介绍了整体断言as const,以及 TypeScript 5.0 起在泛型参数上使用const修饰符来保留字面量精度,我们会在后文展开。

组合字面量:联合类型与类型别名

单独的字面量类型价值有限,它们的真正威力在于组合成联合类型(Union Types)。仓库的 Union Type 章节定义:

联合类型是表示一个值可以是若干类型之一的类型,用|符号连接每种可能的类型。

let x: string | number; x = 'hello'; // 合法 x = 123; // 合法

当字面量类型通过|组合时,就得到一个"取值白名单"。原文档的核心示例:

type O = 'a' | 'b' | 'c';

O只包含'a'、'b'、'c'这三个明确指定的字符串,任何其他字符串都不合法。用集合论的视角看(见 类型系统探索 的"Tipi come insiemi"小节),'a' | 'b' | 'c'就是三个单元素集合的并集(T1 ∪ T2);而T1 extends T2相当于"T1 是 T2 的子集"。

这种"字面量联合"是 TypeScript 表达有限状态集合最自然的方式,比纯字符串类型安全得多:编辑器能给出精确的自动补全,编译器能在赋值时拦截拼写错误,例如:

type O = 'a' | 'b' | 'c'; const x: O = 'A'; // 报错:类型 '"A"' 不能赋给类型 'O'

实战一:用字面量做判别式——可辨识联合(Discriminated Unions)

字面量类型最常见的实战价值,是作为可辨识联合(Discriminated Unions)的判别属性(discriminant)。仓库的 Unioni discriminate 章节定义:

可辨识联合是一种联合类型,它利用一个公共属性(称为判别式)来收窄联合中可能的类型集合。

type Square = { kind: 'square'; // 判别式 size: number; }; type Circle = { kind: 'circle'; // 判别式 radius: number; }; type Shape = Square | Circle; 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); } }; 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

这里的kind属性类型是字面量联合'square' | 'circle'。在switch的case 'square'分支内,TypeScript 会把shape精确收窄为Square,因此可以安全访问shape.size;同理case 'circle'分支内可访问shape.radius。判别式必须使用字面量类型才能触发这种收窄——这正是字面量类型"精确性"的直接体现。

实战二:配合类型收窄(Narrowing)与类型保护(Type Guards)

字面量联合类型与**类型收窄(Narrowing)**天然互补。仓库的 Restringimento 章节定义:

TypeScript 的收窄是在条件块内精化变量类型的过程,在处理联合类型时尤其有用。

该章节列举了多种收窄方式,其中与字面量类型直接相关的有:

相等性收窄(Equality Narrowing)——配合switch与===、!==、==、!=等运算符,按字面量值收窄类型:

const checkStatus = (status: 'success' | 'error') => { switch (status) { case 'success': return true; case 'error': return null; } };

switch的每个case本质上都在与字面量'success'、'error'做相等比较,TypeScript 借此把status收窄到对应的字面量单元素类型。

typeof 收窄(typeof guards)——按 JavaScript 运行时类型收窄,适合原始值联合:

const fn = (x: number | string) => { if (typeof x === 'number') { return x + 1; // 此处 x 是 number } return -1; };

真值收窄(Truthiness Narrowing)——通过变量真假判断收窄:

const toUpperCase = (name: string | null) => { if (name) { return name.toUpperCase(); } else { return null; } };

in运算符收窄与instanceof收窄——分别按属性存在性与构造函数实例判断收窄:

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'; } };
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

此外,类型系统探索 章节还介绍了Array.isArray()等内置守卫,以及当内置手段不够用时,可以用**用户自定义类型保护(type predicates)**来收窄——它本质上是返回布尔值并带有value is T签名的函数。字面量类型是这些收窄操作中最细粒度的"终点类型"之一。

实战三:穷尽性检查(Exhaustiveness Checking)与never

字面量联合类型加上never类型,可以实现著名的穷尽性检查(Exhaustiveness Checking)。仓库的 Controllo di esaustività 章节的定义与示例:

穷尽性检查是 TypeScript 的一项特性,它保证可辨识联合的所有可能分支都在switch或if中被处理。

type Direction = 'up' | 'down'; const move = (direction: Direction) => { switch (direction) { case 'up': console.log('Spostamento verso l\'alto'); break; case 'down': console.log('Spostamento verso il basso'); break; default: const exhaustiveCheck: never = direction; console.log(exhaustiveCheck); // 这行永远不会执行 } };

原理:当'up'与'down'都被case处理完后,default分支里direction的类型已被收窄为never。把never赋给never是合法的,因此当前代码编译通过。一旦有人给Direction联合新增成员(比如'left'),default分支中direction的类型就不再是never,const exhaustiveCheck: never = direction就会报错——编译器立刻提醒你新增的分支尚未处理。这是字面量联合 +never构成的"编译期兜底网络",保证状态演进时不会漏掉任何 case。

实战四:模板字面量联合类型(Template Union Types)

字面量类型还能与**模板字面量类型(Template Literal Types)**结合,在类型系统内直接拼接、生成新的字面量联合。仓库的 Tipi di unione di template 章节示例:

type Status = 'active' | 'inactive'; type Products = 'p1' | 'p2'; type ProductId = `id-${Products}-${Status}`; // 结果为:"id-p1-active" | "id-p1-inactive" | "id-p2-active" | "id-p2-inactive"

模板字面量类型会对嵌入的联合类型做笛卡尔积展开,把2 × 2组合成 4 个字面量成员。这让开发者能在编译期声明并校验诸如路由路径、事件名、ID 格式、CSS 类名等需要"格式约定"的字符串,无需任何运行时校验代码。

让字面量更精确:const断言与泛型const修饰符

前文提到,对象属性默认会被拓宽为宽泛类型。要保留字面量精度,仓库 类型系统探索 章节给出了一套完整的工具链:

对单个属性使用as const:

const v = { x: 3 as const, }; v.x = 3;

对整个对象使用as const:

const v = { x: 1, y: 2, } as const;

对元组使用as const——数组默认推断为可变的number[],加as const后变成只读元组:

const x = [1, 2, 3]; // number[] const y = [1, 2, 3] as const; // readonly [1, 2, 3]

TypeScript 5.0 的泛型const修饰符——在泛型参数上写const,可以让 TypeScript 推断出"最精确的可能类型",从而保留字面量:

// 不使用 const:属性被拓宽 function identity<T>(value: T) { return value; } const values = identity({ a: 'a', b: 'b' }); // 推断结果:{ a: string; b: string; }
// 使用 const 修饰符:属性保留为字面量 function identity<const T>(value: T) { return value; } const values = identity({ a: 'a', b: 'b' }); // 推断结果:{ a: "a"; b: "b"; }

同时该章节强调:如果希望变量类型始终精确,也可以使用显式类型标注,比如const v: { x: 1 | 2 | 3 },让字面量联合作为目标类型直接约束赋值。

小结:字面量类型在 The Concise TypeScript Book 中的位置

字面量类型(字符串、数字、布尔)是 TypeScript 类型系统中最精确的构建块。在 The Concise TypeScript Book 的体系里,它们贯穿多个核心章节:

  • 定义见 Tipi letterali:单元素集合,值是 JavaScript 原始值;
  • 推断规则见 Inferenza letterale:const保留字面量,let/对象属性拓宽,可用as const或as X修复;
  • 组合方式见 Union Type 与 Tipi di unione di template:|组成取值白名单,模板字面量自动展开组合;
  • 应用模式见 Unioni discriminate(判别式)、Restringimento(收窄)、Controllo di esaustività(never兜底);
  • 精度控制见 Esplorazione del sistema di tipi(as const、泛型const修饰符、集合论视角)。

在实际项目中,建议把"需要枚举取值"的字段(状态、方向、类型标签、ID 前缀等)优先声明为字面量联合类型,再配合switch收窄与never穷尽性检查,即可把大量运行期错误提前到编译期拦截——这是 TypeScript 相对 JavaScript 的核心价值之一,也是本书反复强调的实践方向。

  • 文档
  • 教程

【免费下载链接】typescript-book

The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.

项目地址:https://gitcode.com/gh_mirrors/typ/typescript-book
点击查看免费下载
上一篇:Umi Lint 指南:基于 ESLint 与 Stylelint 的开箱即用编码规范实践
下一篇:ThinkPad风扇控制终极指南:掌握128级精准调速,实现智能散热优化

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 2:58:06

基于YOLOv5与ResNet18的骨龄检测双模型方案:从数据到部署

简介&#xff1a;本资源面向计算机视觉方向的本科与研究生毕业设计需求&#xff0c;提供一套基于YOLOv5与ResNet18联合实现的骨龄检测完整工程&#xff0c;适合需要完成高分毕设、课程设计或医学影像入门实践的同学。项目将目标检测与图像分类串联&#xff0c;先定位手骨关键区…

作者头像 李华
网站建设 2026/9/26 2:57:26

Mac装Photoshop‘已损坏’报错终极解决方案

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

作者头像 李华
网站建设 2026/9/26 2:56:36

Baserow 文件上传与存储指南:从文件入库到访问控制

Baserow 文件上传与存储指南&#xff1a;从文件入库到访问控制 【免费下载链接】baserow Build databases, automations, apps & agents with AI — no code. Open source platform available on cloud and self-hosted. GDPR, HIPAA, SOC 2 compliant. Best Airtable alte…

作者头像 李华
网站建设 2026/9/26 2:54:48

浏览器里修图:WebGPU 图像修复工具 inpaint-web 上手记

浏览器里修图&#xff1a;WebGPU 图像修复工具 inpaint-web 上手记 【免费下载链接】inpaint-web A free and open-source inpainting & image-upscaling tool powered by webgpu and wasm on the browser。| 基于 Webgpu 技术和 wasm 技术的免费开源 inpainting & ima…

作者头像 李华