admin管理员组

文章数量:1131652

I'm using some destructuring like this:

const { item } = content
console.log(item)

But how should I handle content === undefined - which will throw an error?

The 'old' way would look like this:

const item = content && content.item

So, if content is undefined -> item will also be undefined.

Can I do something similar using destructuring?

I'm using some destructuring like this:

const { item } = content
console.log(item)

But how should I handle content === undefined - which will throw an error?

The 'old' way would look like this:

const item = content && content.item

So, if content is undefined -> item will also be undefined.

Can I do something similar using destructuring?

Share Improve this question asked Jan 24, 2018 at 22:51 user3142695user3142695 17.3k55 gold badges194 silver badges372 bronze badges 2
  • See also JS destructuring. How to deal with null or undefined values, What does passing arguments in this way mean? – guest271314 Commented Jan 24, 2018 at 23:19
  • 1 I'd love to know why the JavaScript Gods decided this should throw rather than just treating undefined and null on the RHS like {}. Wouldn't that have saved a lot of trouble? – Denis Howe Commented Oct 27, 2023 at 11:52
Add a comment  | 

8 Answers 8

Reset to default 414

You can use short circuit evaluation to supply a default if content is a falsy value, usually undefined or null in this case.

const content = undefined
const { item } = content || {}
console.log(item)                       // undefined

A less idiomatic (see this comment) way is to spread the content into an object before destructuring it, because null and undefined values are ignored.

const content = undefined
const { item } = { ...content }
console.log(item) // undefined

If you are destructuring function params you can supply a default (= {} in the example).

Note: The default value would only be applied if the destructured param is undefined, which means that destructuring null values will throw an error.

const getItem = ({ item } = {}) => item
console.log(getItem({ item: "thing" })) // "thing"
console.log(getItem())                  // undefined

try {
  getItem(null)
} catch(e) {
  console.log(e.message)                // Error - Cannot destructure property `item` of 'undefined' or 'null'.
}

Or even set a default value for the item property if the input object doesn't contain the property

const getItem = ({ item = "default" } = {}) => item
console.log(getItem({ item: "thing" })) // "thing"
console.log(getItem({ foo: "bar" }))    // "default"

const { item } = Object(content)

Destructuring the nested object is clean and short but sucks when source property is null or undefined in right side object

let say we have

const {
  loading,
  data: { getPosts },
} = useQuery(FETCH_POSTS_QUERY);

Solution 1 if we have data object but no getPosts then we can use:
(Setting default at each level)

const {
  loading,
  data: { getPosts = [] } = { getPosts: [] },
} = useQuery(FETCH_POSTS_QUERY);

Solution 2: if event data is undefined then:

const {
  loading,
  data: { getPosts } = { getPosts: [] },
} = useQuery(FETCH_POSTS_QUERY);

There is recently added: Nullish coalescing operator (??).
Which basically returns right-side value, if the left-side value is null or undefined (our case with undefined instead of an object).

const { item } = undefined or null
// Uncaught TypeError: Cannot destructure property 'item' of 'null' as it is  null.

const { item } = content ?? {}
console.log(item)   // undefined

So consider using the operator. Also, as mentioned before in the answers, there is || (or) operator. For us, there is no significant difference in this particular case.

That's just a matter of taste, in our team, we have an agreement: we use ?? for defining default object if the target object is null or undefined, and in other cases we use || operator.

I'll just add that for the OP's use case, it is also possible to use the Optional chaining operator:

const item = content?.item
console.log(item)

If content is null or undefined, then content.item will not be accessed and item will be undefined.

One can unpack undefined value, but can't unpack from undefined.
Fixing it is as easy as setting the default params value.

Example:

(() => {
    // prepare payload
    const PAYLOAD = {
        holdingJustThis: 1
    };
    // lets unpack the payload and more
    const {
        holdingJustThis,
        itIsGoingToBeUndefined,
        itCouldThrowButWont: {
            deep
        } = {}                  // this will secure unpacking "deep"
    } = PAYLOAD;

    console.log({
        holdingJustThis
    });
    console.log({
        itIsGoingToBeUndefined  // logs {itIsGoingToBeUndefined:undefined}
    });
    console.log({
        deep                    // logs {deep:undefined}
    });
})()
const content = undefined
const { item } = content ?? {}
console.log(item)   // undefined           

accepted answer does not work for truely undefined values which were not set by const content = undefined. in such cases this will work:

const { item } = (typeof content !== 'undefined' && content) || {}
console.log(item)

本文标签: javascriptJSES6 Destructuring of undefinedStack Overflow