TypeError: Cannot destructure property of undefined в JavaScript — как исправить

JavaScript Автор: Среда и версия: JavaScript (ECMAScript 2026)
содержание

TypeError: Cannot destructure property 'name' of 'value' as it is undefined означает, что JavaScript получил undefined там, где объектный шаблон ожидал значение для разбора. Ошибка возникает до создания переменных из шаблона: извлекать свойства ещё не из чего.

Чаще всего источник — пропущенный аргумент функции, неудачный поиск конфигурации или ответ API без ожидаемого объекта. Исправление зависит от контракта: необязательному объекту задают осмысленное значение по умолчанию, а обязательный проверяют на границе и отклоняют с понятной ошибкой.

JavaScript / 01

Значение по умолчанию срабатывает только для undefined

Значение по умолчанию срабатывает только для undefined01 connect() undefined → {} timeout → 5000 Сначала срабатывает умолчание всего параметра, затем — свойства. 02 connect(null) null остаётся null → TypeError Проверь входные данные или явно сохрани ошибку. {} не подставится.01connect()undefined → {}timeout → 5000Сначала срабатывает умолчание всегопараметра, затем — свойства.02connect(null)null остаётся null→ TypeErrorПроверь входные данные или явно сохраниошибку. {} не подставится.
В 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)

Как выбрать исправление, которое сохраняет контракт

Сначала определите, что означает отсутствующий объект именно в этом месте:

  1. Если аргумент необязателен и пустой объект — допустимое состояние, используйте function fn({ option } = {}).
  2. Если null и undefined одинаково означают законное отсутствие, нормализуйте значение через value ?? {} до деструктуризации.
  3. Если объект обязателен, проверьте его сразу после API, поиска, чтения конфигурации или входа в публичную функцию и остановите выполнение с понятной ошибкой.
  4. Если отсутствие — отдельный результат операции, обработайте его веткой if и не деструктурируйте до этой проверки.

Запасной объект хорош только тогда, когда он сам соответствует допустимому состоянию. Иначе он убирает стек в точке нарушения, но оставляет программе переменные со значением undefined.

Чем эта ошибка отличается от похожих TypeError

Ошибка деструктуризации относится к шаблону const { name } = value или параметру function fn({ name }): весь источник должен допускать извлечение свойств до того, как появится переменная name.

В Cannot read properties of undefined сбой происходит при обычном доступе value.name. Там ищут отсутствующее значение слева от точки в цепочке. Здесь сначала проверяют целиком правую часть деструктуризации и место, где задано значение по умолчанию.

В Cannot set properties of undefined код пытается записать свойство выражением value.name = 'Анна'. Это не создание переменных по шаблону: исправлять нужно объект-получатель записи или ветку, которая должна была его создать.

Короткий порядок диагностики

  1. Найдите первый кадр стека из своего кода и сам шаблон { ... } слева от = либо в параметрах функции.
  2. Выведите значение справа от = или фактический аргумент до вызова.
  3. Проследите источник undefined или null: пропущенный аргумент, поиск, ключ конфигурации, ответ API или функция без ожидаемого результата.
  4. Решите по контракту, допустимо ли отсутствие всего объекта и отдельных свойств.
  5. Поставьте = {} или ?? {} только для допустимого отсутствия; обязательные данные проверьте на границе.

Главное различие — уровень значения по умолчанию. Внешнее = {} спасает от пропущенного объекта, внутреннее property = value заполняет отсутствующее свойство, а null не запускает ни одно из них автоматически.

Источники