2

I have an object like this

const obj = {
  foo: {
    bar: { // maybe null
      id: 0
    }
  }
};

I want to destructure obj to get id. If bar was only ever undefined or an object this would be sufficient:

const {
        foo: {
          bar: {
            id,
          } = {},
        } = {},
      } = obj;

But when bar is null I get the error Cannot read property 'id' of null.

I could do this, suggested here

const {
        foo: {
          bar = {},
        } = {},
      }      = obj;
const { id } = bar || {};

but this means I would need to destructure every nullable object as a separate statement, which I'd prefer not to do.

Is there a way to make the default initializer for an object run if its value is null?

Matt Foxx Duncan
  • 2,074
  • 3
  • 23
  • 38

1 Answers1

3

You can sort of "hijack" the spread operator. You'll have a not-so-beatiful syntax like but it works:

const obj = {
  foo: {
    bar: null
  }
}

const id = {...{...{...obj}.foo}.bar}.id
// id = undefined

You can add an "or something" to the end to get a default value, like:
const id = {...{...{...obj}.foo}.bar}.id || 42
// id = 42

The principle on how this works is that if you try to spread an undefined or null value, you'll get an empty object:

console.log('spreaded null', { ...null })
// {}

console.log('spreaded undefined', { ...undefined })
// {}

Now, if you access a property that isn't defined on an object, the JS engine will return you undefined, thus, you can spread it to have another empty object to chain the next inner property you need to access.

0xc14m1z
  • 3,675
  • 1
  • 14
  • 23
  • Yikes, its definitely not very readable. This also looks like I will still need a separate statement rather than being able to resolve it inside the original destructuring statement, right? – Matt Foxx Duncan Mar 04 '19 at 19:12