TypeError: Cannot destructure property 'name' of 'value' as it is undefined означает, что JavaScript получил undefined там, где объектный шаблон ожидал значение для разбора. Ошибка возникает до создания переменных из шаблона: извлекать свойства ещё не из чего.
Чаще всего источник — пропущенный аргумент функции, неудачный поиск конфигурации или ответ API без ожидаемого объекта. Исправление зависит от контракта: необязательному объекту задают осмысленное значение по умолчанию, а обязательный проверяют на границе и отклоняют с понятной ошибкой.
Значение по умолчанию срабатывает только для undefined
function connect({ timeout = 5000 } = {}) два независимых значения по умолчанию: первое заменяет весь аргумент только при undefined, второе — отсутствующее свойство timeout.Что именно не удалось деструктурировать
В объектной деструктуризации выражение справа вычисляется раньше, чем свойства связываются с переменными:
const result = undefined
const { name } = result
// TypeError: Cannot destructure property 'name' of 'result' as it is undefined
Формулировка зависит от движка и контекста. В сообщении могут быть Cannot destructure property, Cannot destructure или undefined is not an object. Диагностика одна: найдите значение справа от = либо фактический аргумент, который попал в деструктурированный параметр.
Пустой объект деструктурируется без ошибки, а отсутствующее свойство получает undefined:
const { name } = {}
console.log(name) // undefined
Значит, сбой вызывает не отсутствие свойства name, а всё исходное значение undefined или null. Другие примитивы для объектного шаблона приводятся к объектам; например, из строки можно извлечь length. Но такой код редко соответствует прикладному контракту, поэтому входные данные всё равно стоит проверять по ожидаемой форме.
Пропущенный аргумент функции становится undefined
Если функцию вызывают без аргумента, соответствующий параметр получает undefined. Деструктуризация выполняется при входе в функцию, поэтому тело ещё не успевает запуститься:
function connect({ url, timeout }) {
return openConnection(url, timeout)
}
connect()
// TypeError: Cannot destructure property 'url' of 'undefined'
Если весь объект настроек необязателен, задайте значение по умолчанию самому параметру:
function connect({ timeout = 5000 } = {}) {
return openConnection('/status', timeout)
}
connect()
connect({ timeout: 1000 })
Запись = {} после закрывающей фигурной скобки относится ко всему аргументу. Она срабатывает для connect() и connect(undefined). Внутреннее timeout = 5000 относится только к свойству: оно срабатывает, если свойства нет или его значение равно undefined.
Если url обязателен, пустой объект уже не сохраняет контракт. Функция продолжит работу с url === undefined, и ошибка появится позже. В таком случае принимайте объект целиком, проверяйте его, а затем деструктурируйте:
function connect(options) {
if (options === null || typeof options !== 'object' || Array.isArray(options)) {
throw new TypeError('Параметр options должен быть объектом')
}
const { url, timeout = 5000 } = options
if (typeof url !== 'string' || url.length === 0) {
throw new TypeError('Свойство options.url должно быть непустой строкой')
}
return openConnection(url, timeout)
}
Такая проверка переносит сбой к границе функции и объясняет, какой договор нарушен. Она не нужна перед каждой внутренней деструктуризацией: после проверки остальной код вправе полагаться на форму options.
Почему null не включает значение параметра по умолчанию
Параметр по умолчанию применяется только к undefined. Поэтому connect(null) не превращает null в пустой объект:
function connect({ timeout = 5000 } = {}) {
return timeout
}
connect(undefined) // 5000
connect(null) // TypeError
Это различие сохраняет смысл данных. undefined часто получается из-за пропущенного аргумента, а null нередко передают намеренно как отдельное состояние. Если по контракту оба значения означают «настроек нет», нормализуйте их явно до деструктуризации:
function connect(options) {
const { timeout = 5000 } = options ?? {}
return timeout
}
Такое исправление уместно только при разрешённом отсутствии настроек. Если null означает повреждённый ответ или ошибку вызывающего кода, ?? {} сотрёт полезный сигнал. Тогда оставьте ранний TypeError или выбросьте свой с описанием контракта.
Значение объекта и значение свойства по умолчанию решают разные задачи
Эти две записи не взаимозаменяемы:
const { theme = 'system' } = settings
const { theme } = settings ?? { theme: 'system' }
В первой строке settings обязан существовать. Значение 'system' используется, когда settings.theme отсутствует или равно undefined. Если settings.theme === null, переменная theme тоже получит null.
Во второй строке запасной объект используется при settings === undefined и settings === null. Но если settings существует как {}, свойство theme останется undefined. Обычно намерение яснее в одной записи:
const { theme = 'system' } = settings ?? {}
Здесь settings ?? {} отвечает за отсутствие всего объекта, а theme = 'system' — за отсутствие свойства. Прежде чем совмещать их, решите отдельно, допустимо ли каждое из этих состояний.
Не заменяйте ?? оператором || без причины. Выражение value || {} также подменяет false, 0 и пустую строку. Это расширяет набор принимаемых значений и может скрыть передачу данных неверного типа.
Поиск конфигурации вернул undefined
Чтение по несуществующему ключу и Array.prototype.find() могут вернуть undefined. Ошибка появляется на следующей операции, если результат сразу деструктурируют:
const environments = {
development: { apiUrl: 'http://localhost:3000' },
production: { apiUrl: 'https://api.example.com' },
}
const { apiUrl } = environments[currentEnvironment]
Если неизвестное окружение — ошибка конфигурации, не подставляйте {}. Проверьте результат рядом с поиском:
const environment = environments[currentEnvironment]
if (environment === undefined) {
throw new Error(`Неизвестное окружение: ${currentEnvironment}`)
}
const { apiUrl } = environment
Запасная конфигурация допустима, только если она предусмотрена требованиями. Тогда выберите её явно, чтобы читатель кода видел правило:
const environment = environments[currentEnvironment] ?? environments.development
const { apiUrl } = environment
У find() выбор тот же: законное отсутствие результата обрабатывают отдельной веткой, а обязательный результат проверяют и отклоняют. const { id } = items.find(...) ?? {} лишь заменит раннюю ошибку на id === undefined.
Ответ API проверяйте до деструктуризации
JSON-ответ может быть синтаксически корректным, но содержать null, массив или объект без обязательных полей. Деструктуризация не проверяет прикладную схему. Она только извлекает свойства из полученного значения.
const payload = await response.json()
if (payload === null || typeof payload !== 'object' || Array.isArray(payload)) {
throw new TypeError('Ответ API должен быть объектом')
}
const { user } = payload
if (user === null || typeof user !== 'object' || Array.isArray(user)) {
throw new TypeError('В ответе API отсутствует объект user')
}
const { id, name } = user
В проекте с уже установленным валидатором схем используйте его на границе ответа. Не пишите параллельный набор ручных проверок в каждом потребителе. После единой проверки функции внутри приложения получают данные известной формы и не маскируют сбои через ?? {}.
Иногда API честно возвращает null, например когда поиск ничего не нашёл. Тогда контракт потребителя должен включать эту ветку:
const user = await loadUser(userId)
if (user === null) {
return renderNotFound()
}
const { name } = user
return renderProfile(name)
Как выбрать исправление, которое сохраняет контракт
Сначала определите, что означает отсутствующий объект именно в этом месте:
- Если аргумент необязателен и пустой объект — допустимое состояние, используйте
function fn({ option } = {}). - Если
nullиundefinedодинаково означают законное отсутствие, нормализуйте значение черезvalue ?? {}до деструктуризации. - Если объект обязателен, проверьте его сразу после API, поиска, чтения конфигурации или входа в публичную функцию и остановите выполнение с понятной ошибкой.
- Если отсутствие — отдельный результат операции, обработайте его веткой
ifи не деструктурируйте до этой проверки.
Запасной объект хорош только тогда, когда он сам соответствует допустимому состоянию. Иначе он убирает стек в точке нарушения, но оставляет программе переменные со значением undefined.
Чем эта ошибка отличается от похожих TypeError
Ошибка деструктуризации относится к шаблону const { name } = value или параметру function fn({ name }): весь источник должен допускать извлечение свойств до того, как появится переменная name.
В Cannot read properties of undefined сбой происходит при обычном доступе value.name. Там ищут отсутствующее значение слева от точки в цепочке. Здесь сначала проверяют целиком правую часть деструктуризации и место, где задано значение по умолчанию.
В Cannot set properties of undefined код пытается записать свойство выражением value.name = 'Анна'. Это не создание переменных по шаблону: исправлять нужно объект-получатель записи или ветку, которая должна была его создать.
Короткий порядок диагностики
- Найдите первый кадр стека из своего кода и сам шаблон
{ ... }слева от=либо в параметрах функции. - Выведите значение справа от
=или фактический аргумент до вызова. - Проследите источник
undefinedилиnull: пропущенный аргумент, поиск, ключ конфигурации, ответ API или функция без ожидаемого результата. - Решите по контракту, допустимо ли отсутствие всего объекта и отдельных свойств.
- Поставьте
= {}или?? {}только для допустимого отсутствия; обязательные данные проверьте на границе.
Главное различие — уровень значения по умолчанию. Внешнее = {} спасает от пропущенного объекта, внутреннее property = value заполняет отсутствующее свойство, а null не запускает ни одно из них автоматически.