127

Typescript (or should we say ES) doesn't allow destructuring of null/undefined objects. It throws TypeError.

So, lets say we have something like

let {a,b,c} = D;

where D could be null.

If we need to do conditional destructuring assignment with null-checks then we create boilerplate code for something that was meant to reduce it.

What is the most elegant way of using it in cases like that or should we use destructuring only for guaranteed non-null objects?

4
  • and Typescript does a good job in doing so. Instead of bypassing the type system you should embrace its objectives, which is among other things: Know your types. Commented Jul 20, 2017 at 10:15
  • 1
    could you please be a bit more explicit? some example? how is type system related to this particular problem? (i am familiar with static typing) Commented Jul 20, 2017 at 10:20
  • With a static type system you should know the types of all your variables. The type of a variable must not change during runtime. I don't know how fancy Typescript's type system is, but at least you should know whether D is null or an Object type. Commented Jul 20, 2017 at 10:36
  • 1
    wait wait...but Object can be nullable. What then? Commented Jul 20, 2017 at 11:54

2 Answers 2

209

You can use an empty object as fallback, and if D is null or undefined the assigned variables will be undefined.

const D = null;
const { a, b, c } = D || {};

console.log(a, b, c);

Using typescript you need to add the correct type (or any) to the FALLBACK object (TS playground). For example:

interface Obj {
    a?: string;
    b?: string;
    c?: string;
}

const D = null;
const { a, b, c } = D || {} as Obj;

console.log(a, b, c);

Another option is to use object spread, since spreading null or undefined results in an empty object (see this SO answer).

const D = null;
const { a, b, c } = { ...D };

console.log(a, b, c);

Using typescript you need to add the types to the variable that you spread, and the object that you destructure. For example (TS Playground):

interface Obj {
    a?: string;
    b?: string;
    c?: string;
}

const D = null;
const { a, b, c } = { ...D as any } as Obj;

console.log(a, b, c);

If you need to handle nested destructuring, use defaults:

const D = null;
const { a, a: { z } = {}, b, c } = { ...D };

console.log(a, b, c, z);

Sign up to request clarification or add additional context in comments.

5 Comments

Any ideas about how to do this well in a sub-object? eg: ``` let a = { b: null }; let { b: { c } } = a; // Uncaught SyntaxError: Invalid destructuring assignment target ```
How about nested restructuring? e.g. const { z: { b } } = a; in this case, z is undefined
These options don't work with TypeScript.
I don't know if something about strict type checking changed in Typescript since this answer was posted but as @Organic mentioned these solutions don't work in Typescript currently. When I try to destructure an empty object like this const { a, b, c } = D || {}; I get an error Property 'a' does not exist on type '{}'.
@Dado - Both options work with TS as long as you the add correct types. I've added examples for TS + links to TS Playground.
-1

I discovered this single pipe | syntax wrapped around the curly braces {}. It seems ugly, but it is still helpful in telling me what to expect, while still allowing it to be null. If I didn't add the optional 'any' it was throwing an error, in my use case…

onChange={({
            value,
            label,
          }:
            | {
                value: string
                label: string
              }
            | any) => {
            setValue(value)
          }}

1 Comment

The destructuring does not actually allow null. And if you want to allow null, you should write | null not | any.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.