Оператор ?. звертається до властивості чи викликає метод, лише якщо значення ліворуч не null і не undefined. Інакше весь вираз повертає undefined замість TypeError.
const city = order?.customer?.address?.city;
// раніше
const city = order && order.customer && order.customer.address && order.customer.address.city;
Три форми:
user?.name // властивість
user?.['first-name'] // обчислена властивість чи індекс
callback?.() // виклик, якщо функція існує
user.save?.() // виклик методу, якщо він є
Коротке замикання. Якщо ?. зустрів null/undefined, решта ланцюжка не обчислюється:
null?.a.b.c; // undefined, а не TypeError на .b
user?.profile.update(log()); // log() не викликається, якщо user - null
Поєднання з ?? - значення за замовчуванням:
const theme = settings?.ui?.theme ?? 'light';
const total = response?.meta?.total ?? 0;
Обмеження:
- ліворуч від присвоєння не працює:
user?.name = 'Оля'- синтаксична помилка; - з
newне працює:new Foo?.(); ?.()захищає лише відnull/undefined, а не від «не функції»:{ f: 42 }.f?.()кинеTypeError: f is not a function.
Де ?. приховує помилки:
function renderInvoice(order) {
const total = order?.items?.reduce((sum, item) => sum + item.price, 0);
return `Разом: ${total} грн`; // 'Разом: undefined грн'
}
Якщо order не повинен бути порожнім, ?. ховає баг: замість зрозумілої помилки в місці, де дані зламалися, отримуємо undefined у інтерфейсі чи NaN у розрахунку - далеко від справжньої причини.
Правило: ?. - для значень, відсутність яких очікувана й нормальна (необов'язкові поля API, опційні колбеки, елемент, якого може не бути на сторінці). Для обов'язкових даних краще явна перевірка з помилкою на вході:
if (!order) throw new Error('Замовлення не завантажено');
TypeScript робить це правило природним: для необов'язкових типів (address?: Address) він вимагає ?., а для обов'язкових - не дозволяє безпідставно сподіватися на «а раптом там null».
Аналог у PHP 8 - nullsafe-оператор $order?->customer?->address.