TypeScript 中的 ?. 运算符:它如何工作以及它的真实名称

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:困扰新手的问题

\n

你是否曾经在编写 TypeScript 时遇到过类似 Cannot read property 'name' of undefined 的错误?很熟悉吧,对吧?尤其是在处理来自服务器的数据或深度嵌套的对象时。正是在这些时刻,你会问:“TypeScript 中是否有一个运算符可以安全地访问属性,而不用担心程序崩溃?”

\n

在 Stack Overflow 上,这个问题已经积累了数千次浏览。答案是——是的,有这样的运算符。而且,它在 JavaScript 中也有(从 ES2020 开始),并且在 TypeScript 中它“开箱即用”。它被称为 optional chaining(可选链),看起来就像大家熟悉的 ?.。在本文中,我们不仅会介绍如何使用它,还会深入底层:看看 TypeScript 编译器如何将这个优雅的语法转换为安全的 JavaScript 代码。

\n\n

TypeScript 中的 ?. 运算符叫什么?

\n

首先,我们从最重要的开始。在开发者社区中,这个运算符有不同的叫法:

\n
    \n
  • Optional chaining(可选链)—— ECMAScript 规范中的官方名称。
  • \n
  • 安全访问运算符(Safe navigation operator)—— 来自其他语言,例如 C# 和 Swift。
  • \n
  • Null 条件运算符(Null-conditional operator)—— 出现在微软的文档中。
  • \n
\n

但本质是一样的:?. 允许你访问对象的属性,如果对象是 null 或 undefined,那么不会抛出错误,而是简单地返回 undefined。这不是魔法,而是一种语法糖,使代码更简洁、更安全。

\n\n

基本语法

\n

语法非常简单。与其这样写:

\n
if (user && user.profile && user.profile.name) {\n    console.log(user.profile.name);\n}
\n

你可以这样写:

\n
console.log(user?.profile?.name);
\n

如果 user 是 undefined,那么整个链式调用会中断,并在控制台输出 undefined。没有错误,没有多余的检查。太棒了!

\n\n

底层工作原理:TypeScript 编译为 JavaScript

\n

TypeScript 是 JavaScript 的超集。它不直接执行代码,而是将其编译为普通的 JS。因此,让我们看看我们优雅的 user?.profile?.name 在编译后会变成什么。

\n\n

示例:简单的 optional chaining

\n

TypeScript 源代码:

\n
const name = user?.profile?.name;
\n

编译后(目标为 ES5):

\n
var name = user === null || user === void 0 ? void 0 : user.profile === null || user.profile === void 0 ? void 0 : user.profile.name;
\n

这里发生了什么?编译器生成了一个三元运算符,它检查每个嵌套层级是否为 null 或 undefined。如果值是 null 或 undefined,则返回 void 0(这是在旧引擎上可靠获取 undefined 的一种方式)。如果不是,则继续。本质上,这就是我们以前手动编写的代码,但现在由机器生成。

\n\n

示例:带函数调用的 optional chaining

\n

?. 运算符不仅适用于属性,也适用于函数调用。假设我们有一个可能不存在的 getAddress 方法:

\n
const address = user?.getAddress?.();
\n

编译后:

\n
var address = user === null || user === void 0 ? void 0 : (typeof user.getAddress === "function" ? user.getAddress() : void 0);
\n

请注意:编译器不仅检查 null,还会确认 getAddress 是一个函数,然后才调用它。如果它不是函数,则返回 undefined。

博客

书籍推荐