TypeScript 可选链

访问嵌套对象时,任何一层是 null/undefined 都会抛错。可选链操作符 ?. 在读取前先做检查:若左侧是 null 或 undefined,整个表达式直接返回 undefined,而不是抛异常,省掉层层 if 判空,代码更清爽。

属性访问的基本用法

传统写法与可选链对比:

interface User {
  address?: { city?: string };
}
const user: User = {};

// 传统写法:每层都要判空
let city1 = user.address ? user.address.city : undefined;
// 可选链写法:一行搞定
let city2 = user.address?.city;

console.log(city2);                             // 输出:undefined
console.log(user.address?.city?.toUpperCase()); // 输出:undefined

?. 只保护它前面的那一层,链条中每一处都可以独立使用 ?.

可选方法调用

对象上的方法可能不存在(可选方法、第三方返回值),用 ?.() 安全调用:

type Config = { init?: () => void; run: () => void };

const a: Config = { run: () => console.log("直接运行") };
const b: Config = {
  init: () => console.log("初始化"),
  run: () => console.log("运行")
};

a.init?.(); // init 不存在,直接跳过,无输出
b.init?.(); // 输出:初始化
b.run();    // 输出:运行

可选元素访问

数组越界、索引值可能不存在时,用 ?.[]

const list: number[][] = [[1, 2], [], [7, 8, 9]];

console.log(list[0]?.[1]); // 输出:2
console.log(list[1]?.[0]); // 输出:undefined(空数组)
console.log(list[2]?.[3]); // 输出:undefined(越界)

const map: Record<string, number> = {};
console.log(map?.["count"]); // 输出:undefined(键不存在)

与空值合并运算符搭配

?. 短路后得到 undefined,常用 ?? 提供默认值:

const user = { name: "小李", profile: null };

const nickname = user.profile?.nickname ?? "游客";
console.log(nickname); // 输出:游客

const price = { current: 0 };
console.log(price.current ?? 99); // 输出:0(?? 不处理 0 和空字符串)

注意 ??|| 的区别:只有 null/undefined 才会触发默认值,0、空字符串不会被替换。

使用注意点

  1. ?. 不能出现在赋值左侧,如 user.address?.city = "x" 会报错。
  2. 短路后右侧不再执行:obj 为空时 obj?.a() 里的 a() 不会被调用。
  3. 别过度使用:只对「确实可缺省」的字段使用,以免空值悄悄溜走。
const doc: { content?: { text?: string } } = {};
const text = doc.content?.text ?? "(无内容)";
console.log(text); // 输出:(无内容)

小结:可选链 ?. 把嵌套判空压缩成一行,配合 ?? 处理默认值即可优雅防御空值;它本质是语法糖,运行时仍是普通的短路检查。

笔记加载中…