Avatar ·

Поддерживает ли TypeScript оператор ?. (опциональная цепочка) и как он называется?

Всем привет! Я начинающий разработчик на TypeScript и столкнулся с проблемой при работе с вложенными объектами. У меня есть интерфейс User, который содержит необязательное поле address, а внутри address есть необязательное поле street. Когда я пытаюсь получить значение street, TypeScript выдает ошибку, если address равен undefined. Вот пример моего кода: ```typescript interface Address { street?: string; city: string; } interface User { name: string; address?: Address; } const user: User = { name: "Иван" }; // Ошибка: Object is possibly 'undefined' console.log(user.address.street); ``` Я слышал, что в JavaScript есть оператор ?., который позволяет безопасно обращаться к свойствам вложенных объектов. Но я не уверен, поддерживает ли его TypeScript. Если да, то как он правильно называется? И можно ли его использовать в моем случае? Буду благодарен за примеры и объяснение, так как в документации я запутался. <<>>

Да, TypeScript поддерживает оператор опциональной цепочки (Optional Chaining)

Оператор ?. (опциональная цепочка) полностью поддерживается в TypeScript, начиная с версии 3.7. Он позволяет безопасно обращаться к свойствам вложенных объектов, не проверяя каждое звено цепочки на null или undefined. Если какая-либо часть цепочки оказывается null или undefined, выражение возвращает undefined вместо выбрасывания ошибки.

Как это работает в вашем примере

Ваш код можно исправить всего одной строчкой:

// Вместо user.address.street используйте:
console.log(user.address?.street); // Выведет: undefined

Если user.address равен undefined, оператор ?. останавливает выполнение цепочки и возвращает undefined. При этом TypeScript корректно выводит тип результата как string | undefined.

Другие варианты использования

  • Динамический доступ к свойствам: obj?.[propName]
  • Вызов функций: func?.() — вызовет функцию, только если она существует
  • Комбинация с оператором нулевого слияния (??):
const street = user.address?.street ?? "Улица не указана";
console.log(street); // Выведет: "Улица не указана"

Важные нюансы

  • Короткое замыкание: Если user.address — undefined, то user.address?.street не будет даже пытаться обратиться к street. Это повышает производительность и предотвращает ошибки.
  • Работа с типами: TypeScript автоматически обновляет типы. Если address — Address | undefined, то после ?. тип street станет string | undefined.
  • Не путайте с оператором "!" (non-null assertion): user.address!.street — это опасный оператор, который говорит TypeScript "я уверен, что значение не null/undefined". Используйте его только когда точно знаете, что значение существует, иначе получите runtime-ошибку.

Полный пример с обработкой

interface Address {
  street?: string;
  city: string;
}

interface User {
  name: string;
  address?: Address;
}

function getStreet(user: User): string {
  return user.address?.street ?? "Адрес не указан";
}

const user1: User = { name: "Иван" };
const user2: User = { name: "Мария", address: { city: "Москва" } };
const user3: User = { name: "Петр", address: { city: "СПб", street: "Невский" } };

console.log(getStreet(user1)); // "Адрес не указан"
console.log(getStreet(user2)); // "Адрес не указан" (street не определен)
console.log(getStreet(user3)); // "Невский"

Название оператора: В русскоязычной документации его чаще всего называют "опциональная цепочка" (от английского "Optional Chaining"). Иногда встречается "условный доступ к свойству" или "безопасная навигация".

Совет для начинающих

Оператор ?. — это синтаксический сахар. Под капотом он превращается в проверки вида obj === null || obj === undefined ? undefined : obj.prop. Используйте его всегда, когда работаете с необязательными полями или API-ответами, которые могут содержать null.

<<>>

Альтернативный подход: использование оператора "!" (Non-null Assertion)

Если вы уверены, что свойство address точно существует в конкретном контексте (например, после проверки), можно использовать оператор "!" (утверждение не-null). Однако это небезопасно и может привести к runtime-ошибкам:

// Опасно! Используйте только если точно знаете, что address существует
console.log(user.address!.street); // Если address undefined — ошибка в рантайме

Проверка через if или тернарный оператор

До появления ?. разработчики использовали ручные проверки:

// Старый способ
if (user.address && user.address.street) {
  console.log(user.address.street);
}

// Или с тернарным оператором
const street = user.address ? user.address.street : undefined;

Когда стоит использовать альтернативы

  • Если нужна поддержка старых версий TypeScript (до 3.7): используйте проверки через if или библиотеки вроде Lodash (_.get(user, 'address.street')).
  • Если нужно выполнить несколько действий при наличии значения: проверка через if может быть нагляднее, чем цепочка ?. с ??.
  • В сложной логике с несколькими вложенными объектами: комбинируйте ?. с деструктуризацией:
const { street } = user.address ?? {};
console.log(street); // undefined, если address нет

Рекомендация: В современном TypeScript (3.7+) отдавайте предпочтение оператору ?. — он чище, короче и менее подвержен ошибкам.