编程前端开发工程师

TypeScript 中的可选链(optional chaining)机制是如何工作的?它解决了哪些问题,使用时在哪些情况下可能导致错误?

用 Hintsage AI 助手通过面试

答案。

可选链机制(?.)在 JavaScript 中出现,以方便安全地访问可能未定义的对象的属性和方法。在 TypeScript 中,它特别有用,因为可以帮助避免与访问 undefinednull 的属性或方法相关的运行时错误。

问题背景

在可选链出现之前,开发者必须手动检查每个嵌套对象层级的存在性,这使得代码冗长且难以阅读:

if (obj && obj.a && obj.a.b) { // ... }

问题

访问未定义对象的嵌套属性时可能会出现运行时错误:Cannot read property 'x' of undefined。此外,冗长的检查链会使代码的维护和理解变得困难。

解决方案

可选链(?.)允许访问嵌套属性、方法或数组元素,如果链中任何部分为 nullundefined,则自动返回 undefined

代码示例:

interface User { name: string; address?: { city?: string; }; } const user: User = { name: 'Ivan' }; console.log(user.address?.city); // undefined

关键特性:

  • 允许编写简洁、安全且易于理解的代码。
  • 适用于访问属性、方法和数组索引。
  • 返回值类型为 T | undefined,TypeScript 编译器会考虑这一点并帮助避免错误。

隐含问题。

可选链可以在赋值运算符的左侧使用吗?例如:user.address?.city = 'Moscow'

不可以,可选链不能在赋值表达式的左侧使用,这将引发编译错误。可选链仅在读取时有效,而不用于写入。

可以使用可选链调用方法吗,如果对象本身可能未定义?例如:user?.logInfo()

可以,如果对象在方法调用的前面可能是 undefined/null,则调用 user?.logInfo() 不会引发错误,且如果 user 未定义将简单返回 undefined

user?.logInfo(); // 如果 user 已定义,则调用 logInfo,否则不做任何操作

可选链与旧式 && 运算符(例如:user && user.address && user.address.city)有什么区别?

可选链更简洁,适用于所有类型(包括方法和数组),而且 TypeScript 在类型检查时会考虑可选链。重要的是,使用 && 运算符时,您可能意外地得到不是真/假或 undefined 的嵌套值。而可选链保证要么返回预期的类型,要么返回 undefined,这在类型推导时会得到体现。

常见错误和反模式

  • 认为可选链会在赋值时 "创建" 嵌套对象——这并非如此。
  • 在类型上永远不可能为 undefined/null 的变量上使用可选链(多余且无用的代码)。
  • 习惯于无脑地在各处使用可选链,这会使代码进一步维护变得困难。

生活中的例子

消极案例

在代码中,即使变量在业务逻辑上始终被定义,也存在冗长的可选链:

order?.customer?.address?.city = 'London';

优点:

  • 保护免受可能的错误,如果属性真的未定义。

缺点:

  • 如果任一属性缺失,则赋值不会发生,且没有通知或错误处理;会出现 "隐性" 逻辑,导致代码混乱。

积极案例

仅在处理外部数据或值确实可能未定义的地方使用可选链:

const city = apiResponse?.info?.location?.city || 'Unknown';

优点:

  • 在处理不完整或意外变化的对象时安全工作,不会抛出异常。
  • 易于阅读和维护的代码。

缺点:

  • 如果需要知道值缺失的原因,则需要进行明确的错误处理。