空值合并(??)和可选链(?.)是 TypeScript 中与类型系统深度协同的容错机制:?? 仅在 null/undefined 时取默认值,保留 0/""/false;?. 安全访问但返回 T | undefined,需配合 ?? 或类型守卫确保后续操作类型安全。

在 TypeScript 中,空值合并(??)和可选链(?.)不是“语法糖”而已,它们是类型系统深度协同的容错机制。关键不在于怎么写,而在于怎么让类型推导自然成立、避免手动断言或绕过检查。
用 ?? 给 undefined/null 提供默认值,而非用 ||
空值合并运算符只在左侧为 null 或 undefined 时才启用右侧默认值,对 false、0、"" 等有效假值完全保留——这正是类型安全的前提。
- ✅ 正确:确保变量有确定类型,比如
string | undefined→string - ❌ 错误:用
||替代,会导致0被误判为“空”,类型虽能过,逻辑已错 - ? 建议搭配类型注解显式声明意图,例如:
const timeout = config?.timeout ?? 5000; // number
用 ?. 安全访问深层属性,但别让它“悬空”
可选链本身返回 T | undefined,如果后续操作(如遍历、调用方法)需要非空类型,仅靠 ?. 不够——它只是防止运行时报错,不解决类型检查问题。
- ✅ 正确:配合
??或类型守卫收口,例如:const items = data?.list ?? [];→ 得到确定的Item[] - ❌ 错误:直接在
for循环中用arr?.length,TS 仍报Object is possibly 'undefined' - ? 数组遍历推荐写法:
for (const item of props.nodes ?? []) { ... }或(props.nodes || []).forEach(...)(后者类型弱,不推荐)
组合使用时注意优先级与括号
?. 和 ?? 的结合很常见,但运算符优先级容易引发隐性错误。TS 规定 ?? 优先级低于 ?. ,所以 a?.b ?? c 等价于 (a?.b) ?? c,这是安全的;但涉及更复杂表达式时需加括号。
立即学习“Java免费学习笔记(深入)”;
- ✅ 明确语义:
user?.profile?.avatarUrl ?? '/default-avatar.png' - ⚠️ 需括号的情况:
(response?.data?.items ?? []).map(...)—— 避免??被误认为只作用于items而非整个路径 - ? 对象解构中慎用可选链:
不支持const { name } = user?.profile ?? {}(语法错误),应改用const { name } = user?.profile || {},但注意类型丢失;更优解是先赋默认值再解构
避免类型断言,用结构化默认值替代 !
看到 TS2532 就加 ! 是最危险的习惯。它绕过类型检查,把隐患留到运行时。
- ✅ 推荐模式:提前归一化数据形态
const links = (props.Data?.nodes ?? []).filter(Boolean); - ❌ 反模式:
props.Data!.nodes!.map(...)—— 一旦 props.Data 为空,运行时崩溃 - ? 在组件 props 或 API 响应处理中,建议封装一个工具函数:
function safeArray<t>(arr: T[] | undefined | null): T[] { return arr ?? []; }</t>,复用且语义清晰


















