- 文档
- 教程
【免费下载链接】typescript-book
The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.
strictNullChecks是 TypeScript 编译器中最影响日常开发体验的选项之一:它决定了null与undefined是否会被当作普通值参与类型系统,还是被严格隔离、仅在显式声明时才允许出现。本文以《The Concise TypeScript Book》中 strictNullChecks 章节 为核心,结合仓库内类型系统、配置与配套语法章节,系统讲解该选项的语义、配置方式、与null/undefined类型的关系,以及在实际代码中配合使用的!、?.、??等工具,帮助你彻底掌控空值处理。
strictNullChecks 是什么
根据 strictnullchecks.md 的定义,strictNullChecks是 TypeScript 编译器的一个选项,它强制进行严格的空值检查(enforces strict null checking)。
当该选项被启用时,变量(variable)和参数(parameter)只有在显式声明其类型为null | undefined联合类型时,才允许被赋值为null或undefined。反过来,如果某个变量或参数没有被显式声明为可空(nullable),TypeScript 就会在编译期生成错误,从而提前阻止潜在的运行时错误(runtime errors)。
这一行为可以概括为两条规则:
- 显式声明才能赋值:可空性必须通过联合类型
null | undefined明确写出,编译器才允许传入空值; - 未声明即报错:任何未显式声明为可空的变量或参数接收到
null/undefined时,编译直接失败。
例如在严格模式下,下面的代码会报错:
// 显式声明为可空:合法 const maybeName: string | null = null; // 未声明为可空:TypeScript 编译错误 // Type 'null' is not assignable to type 'string' const name: string = null;这正是该选项的价值所在:将“空值可能随时出现”这一隐患从运行时提前到编译期,强制开发者显式处理空值路径。
在类型系统中的地位:null 与 undefined 的语义
要理解strictNullChecks,先要理解null与undefined在 TypeScript 类型系统中的语义。根据 primitive-types.md 的说明:
undefined表示值未被赋值或初始化,即“非有意的值缺失”(unintentional absence of value);null表示我们明确知道该字段没有值,即“有意的值缺失”(intentional absence of value)。
在 exploring-the-type-system.md 的“类型作为集合”章节中,undefined和null被归类为单元素集合(Single element set),与never(空集合)、boolean/union(有限集合)、string/number/object(无限集合)、any/unknown(全集)并列。这意味着每个空值类型只包含一个可能的取值,它们的可赋值规则非常明确。
更关键的是,该书在同一章节明确给出了strictNullChecks对这两个类型行为的决定性影响:
请注意,当启用
strictNullChecks时,null和undefined的处理方式与void类似;否则,它们与never类似。
这段话揭示了两种模式下的本质差异:
| 编译选项状态 | null/undefined的表现 | 实际效果 |
|---|---|---|
strictNullChecks启用 | 类似void,是类型系统中真实存在的值类型 | 只有显式声明为null/undefined或与之联合的变量才能接收空值 |
strictNullChecks禁用 | 类似never,可以被赋值给任意类型 | 任何类型都“假装”接受null/undefined,空值检查形同虚设 |
也就是说,关闭该选项后,null和undefined几乎可以赋给任何类型(像never一样具有极强的可赋值性),此时类型系统无法约束空值的扩散;而开启后,它们被限制在显式声明的联合类型内,类型系统得以精准追踪每个可空位置。
如何启用:tsconfig.json 与 CLI
strictNullChecks的启用方式有两种:写入tsconfig.json,或通过tsc命令行参数传递。在日常项目中,推荐将其纳入strict严格模式统一管理。
通过 strict 严格模式启用
本项目tools目录下的 tsconfig.json 是实际启用了严格模式的示例:
{ "compilerOptions": { "target": "es2022", "module": "commonjs", "noImplicitAny": true, "esModuleInterop": true, "noEmitOnError": true, "moduleDetection": "force", "noUnusedLocals": false, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "lib": ["es2022", "esnext.disposable", "esnext.decorators", "dom"] } }其中第 11 行的"strict": true会一次性启用包括strictNullChecks在内的一组严格检查选项。网站部分则在 website/tsconfig.json 中通过继承 Astro 的严格预设开启:
{ "extends": "astro/tsconfigs/strict" }单独开启或关闭
如果不想启用整套严格模式,也可以只针对该选项单独配置:
{ "compilerOptions": { "strictNullChecks": true } }将值改为false则单独关闭空值检查。同样的效果可以通过 CLI 达成:
tsc --strictNullChecks需要说明的是:strictNullChecks的效果与项目实际使用的 TypeScript 版本密切相关,本文讨论的行为以仓库 tools/package.json 中锁定的typescript ^5.4.5为基准。
开启前后的行为对比
结合 exploring-the-type-system.md 中“记住这些规则”一节的赋值示例,可以看到可赋值性的完整图谱:
let a: number = 1; let b: number = 2; a = b; // 合法:一切都可以赋值给自己 let c: any; c = 1; // 合法:所有类型都可以赋给 any let d: unknown; d = 1; // 合法:所有类型都可以赋给 unknown let e: unknown; let e1: unknown = e; // 合法:unknown 只能赋给自身和 any let e2: any = e; // 合法 let e3: number = e; // 非法 let f: never; f = 1; // 非法:没有任何值可以赋给 never let g: void; let g1: any; g = 1; // 非法:void 除了 any 之外不接受也不可赋给任何类型 g = g1; // 合法结合该章节的注释可以得出:在启用strictNullChecks的项目中,null与undefined的赋值行为应当类比void——它们只在显式声明的上下文中流转,不会“悄悄”渗入其他类型。这也是为什么开启后,类似document.getElementById(...)的 API 返回值会包含null分支,从而迫使开发者处理“元素可能不存在”的路径。
实际开发中的配套工具
启用strictNullChecks后,空值会频繁出现在类型中,TypeScript 也提供了配套语法让处理更简洁。《The Concise TypeScript Book》在 others.md 中系统介绍了这些工具。
Non-null Assertion 运算符(后置!)
后置!用于向编译器断言某个变量或属性不是null或undefined,即便静态类型分析认为它可能是。该功能可以消除一部分显式的空值检查:
type Person = { name: string; }; const printName = (person?: Person) => { console.log(`Name is ${person!.name}`); };如上例所示,person是可选参数(类型为Person | undefined),通过person!.name我们向编译器承诺此时person必然存在。需要强调的是,!只是编译期断言,不产生任何运行时保护——若实际值为空,运行时依然会抛错,因此应谨慎使用。
可选链?.
可选链运算符?.与普通点运算符.用法类似,区别在于它安全地处理null/undefined:当左侧值为空时,整个表达式短路并返回undefined,而不是抛出错误:
type Person = { name: string; age?: number; address?: { street?: string; city?: string; }; }; const person: Person = { name: 'John', }; console.log(person.address?.city); // undefined在严格空值检查下,person.address的类型是{ street?: string; city?: string } | undefined,?.让我们无需逐层if判断即可安全访问深层属性。
空值合并运算符??
空值合并运算符??在左侧为null或undefined时返回右侧值,否则返回左侧值——注意它只对null/undefined生效,不会像||那样把0、''、false等 falsy 值一并替换:
const foo = null ?? 'foo'; console.log(foo); // foo const baz = 1 ?? 'baz'; const baz2 = 0 ?? 'baz'; console.log(baz); // 1 console.log(baz2); // 0??与strictNullChecks配合是“为可空值提供默认值”的标准写法,且不会误伤合法的 falsy 值。
可选属性?与类型收窄
除了上述运算符,书中 optional-properties.md 章节讲解的可选属性语法prop?: T本质上是prop: T | undefined,与strictNullChecks直接相关。同时,narrowing.md 与 control-flow-analysis.md 介绍了通过typeof检查、truthiness 判断、in运算符、instanceof等方式在代码流中收窄可空类型的方法,例如:
let x: number | undefined = 10; if (x !== undefined) { x += 100; // 此处 x 已被收窄为 number }这类控制流收窄是strictNullChecks模式下处理空值的主力手段,能让代码在保持安全的同时清晰表达“空值已被排除”的意图。
在本书中的位置与延伸阅读
strictNullChecks在《The Concise TypeScript Book》中位于 目录 的第 19 章,紧随 “Literal Inference” 之后,处于类型系统基础概念向进阶类型语法过渡的关键位置。围绕它,书中提供了完整的知识链路:
- 前置基础:primitive-types.md(
null/undefined语义)、exploring-the-type-system.md(类型系统与可赋值性); - 核心章节:strictnullchecks.md(本文主题);
- 进阶衔接:narrowing.md(空值收窄)、optional-properties.md(可选属性)、unknown-type.md(类型安全的
unknown)、the-never-type.md(never与穷尽性检查)。
此外,本书为多语言开源项目,本文依据的保加利亚语章节与英文原版 strictnullchecks.md 内容一致;除保加利亚语外,网站内容目录 下还维护了阿拉伯语、中文、日语、韩语、俄语等十余种语言的对应章节,便于不同语言背景的读者对照学习。
小结
strictNullChecks是 TypeScript 严格模式中最具“行为改变力”的开关:开启后,null与undefined从可随意赋值的“隐形值”变为必须显式声明才能出现的“一等类型”,其行为类比void;关闭时则退化为类似never的宽松语义。配合!、?.、??以及控制流收窄,开发者可以在编译期获得完整的空值追踪能力,将大量运行时崩溃前置为编译错误——这正是 TypeScript 相比纯 JavaScript 的核心价值之一。
- 文档
- 教程
【免费下载链接】typescript-book
The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.
相关推荐
TypeScript Book 实战指南:strictNullChecks 严格空值检查全面解析
TypeScript Book 实战指南:strictNullChecks 严格空值检查全面解析 本文是《TypeScript Book》开源仓库中 docs/
教程TypeScript strictNullChecks 严格空值检查详解:以 The Concise TypeScript Book 项目为实践范本
TypeScript strictNullChecks 严格空值检查详解:以 The Concise TypeScript Book 项目为实践范本 stric
文档教程如何开启Flow严格模式:提升JavaScript代码质量的完整指南
如何开启Flow严格模式:提升JavaScript代码质量的完整指南 Flow是一个为JavaScript添加静态类型检查的工具,能够显著提升开发者生产力和代码
开发工具静态分析代码质量
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考