TypeScript 中的运算符 ?. 是什么

问号点 ?. 语法在 TypeScript 中称为可选链接,就像使用点表示法访问对象的嵌套属性一样,但如果引用为空,它不会导致错误,而是短路返回未定义。

type Person = {
  address?: {
    country?: string;
  };

  name?: {
    first?: string;
  };
};

const person: Person = {
  address: {
    country: 'Chile',
  },
};

console.log(person.address?.country); // ?️ "Chile"

console.log(person.name?.first); // ?️ undefined

我们创建了一个类型,其中地址和名称属性是可选的。

大多数情况下,您将从数据库中获取此数据或从文件中读取数据,其中某些属性可能没有值。

第一个 console.log 语句使用可选的链接 (?.) 运算符来访问 person 对象的 address.country 属性。

因为 address.country 属性存在于 person 对象上,所以它的值被记录到控制台。

第二个示例使用可选链接 (?.) 运算符访问 person 对象上的 name.first 属性,但由于该属性在对象上不存在,可选链接 (?.) 运算符返回 undefined。

每当我们尝试使用 nullishnull 或 undefined)引用访问属性时,可选的链接运算符 (?.) 会短路返回 undefined 而不是抛出错误。

如果我们没有使用可选链操作符,我们会得到一个错误,因为我们试图访问一个 undefined 值的属性。

type Person = {
  address?: {
    country?: string;
  };

  name?: {
    first?: string;
  };
};

const person: Person = {
  address: {
    country: 'Chile',
  },
};


// ⛔️ ERROR: Cannot read properties of undefined (reading 'first')
console.log(person.name.first); // ?️ undefined

TypeScript 中的运算符 ?. 是什么

如果未设置 name 属性,我们没有使用可选链接 (?.) 运算符进行短路,因此出现错误。

我们过去可能使用过逻辑 AND (&&) 运算符来解决此问题。

type Person = {
  address?: {
    country?: string;
  };

  name?: {
    first?: string;
  };
};

const person: Person = {
  address: {
    country: 'Chile',
  },
};

console.log(person.name && person.name.first); // ?️ undefined

我们使用逻辑 AND (&&) 运算符来检查访问 person 对象上的 name 属性是否返回真值,如果是,我们可以尝试访问 name 对象上的第一个属性。

这与使用可选链接有点不同,因为它检查引用是否真实,而可选链接 (?.) 运算符检查引用是否为空或未定义。

如果引用为 null 或 undefined,可选的链接运算符也可用于访问特定索引或短路处的数组元素。

type Person = {
  numbers?: {
    low?: number[];
  };
};

const person: Person = {};

console.log(person.numbers?.low?.[0]); // ?️ undefined

low 属性可能未定义,因此尝试访问未定义值的索引 0 处的数组元素会引发错误,除非我们使用可选链接 (?.) 运算符在引用未定义的情况下进行短路。

如果在对象上填充了属性,则可选的链接运算符将返回数组中的特定值。

type Person = {
  numbers?: {
    low?: number[];
  };
};

const person: Person = {
  numbers: {
    low: [1, 2, 3],
  },
};

console.log(person.numbers?.low?.[0]); // ?️ 1

如果函数的值不等于 null 或 undefined,则可选链 (?.) 运算符也可用于调用函数。

function logger(callback?: (msg: string) => void) {
  callback?.('hello');
}

logger(console.log); // ?️ "hello"

如果未提供回调参数,尝试调用回调参数将导致错误,因此我们使用可选链接 (?.) 运算符在调用函数之前检查引用是否为 null 或 undefined

如果未提供参数,则操作员只会短路返回 undefined 而不是调用函数。