Как избежать ошибки при обращении к свойству объекта, если объект undefined?
Что проверяют
Знаете ли вы, почему падает TypeError: Cannot read properties of undefined, и умеете ли выбрать защиту по ситуации, а не по привычке. Следом обычно спрашивают, чем ?? отличается от || и не прячет ли опциональная цепочка настоящую ошибку.
Как отвечать
Начните с причины: ошибку даёт обращение к свойству у undefined или null, а чтение несуществующего свойства у обычного объекта просто возвращает undefined. Дальше способы:
- опциональная цепочка
?.:user?.profile?.nameвернётundefined, как только встретитnullилиundefined, и дальше не пойдёт. Работает и для вызовов (onClose?.()), и для индексов (items?.[0]). Это стандарт ES2020, его понимают все современные браузеры и TypeScript; - оператор
??: значение по умолчанию только дляnullиundefined:user?.name ?? 'Гость'. В отличие от||, не затирает0, пустую строку иfalse; - явная проверка:
if (!user) returnв начале функции. Хороша, когда отсутствие объекта это отдельная ветка логики; - деструктуризация с дефолтом:
const { name = 'Гость' } = user ?? {}. Дефолт срабатывает только наundefined, наnullнет; - типы: TypeScript со
strictNullChecksзаставит обработатьUser | undefinedещё до запуска.
Во фронтенде самый частый случай это данные, которые ещё не пришли: data.items.map(...) в первом рендере. Тут правильнее показать состояние загрузки, чем размазывать ?. по всему шаблону.
Где спотыкаются
Ставят ?. везде подряд. Если объект обязан существовать, его отсутствие это баг, и цепочка молча превратит падение в пустой экран, который труднее отлаживать.
Путают || и ??: count || 10 превратит законный ноль в десять, а price || 'нет цены' покажет «нет цены» у бесплатного товара.
Думают, что ?. защищает всю цепочку. user?.profile.name упадёт, если user есть, а profile нет: оператор проверяет только то, что стоит прямо перед ним.