DEV Community

Michael Z
Michael Z

Posted on • Originally published at michaelzanggl.com

Namespaces are just fine - No need to destructure every object in JavaScript

An increasingly common practice in JavaScript is destructuring. This is great to get rid of otherwise generic terms like in the following examples.

Destructuring objects:

/*❌*/ const results = await fetch('users')
/*❌*/ results.users
/*✔️*/ const { users } = await fetch('users')
Enter fullscreen mode Exit fullscreen mode

Destructuring arrays:

/*❌*/ const results = await validate(request)
/*❌*/ if (!results[0]) throw results[1]
/*✔️*/ const [isSuccessful, error] = await validate(request)
/*✔️*/ if (!isSuccessful) throw error
Enter fullscreen mode Exit fullscreen mode

These are very good use-cases for destructuring!

But then there is the other side of the coin:

const { user: { city }} = results
Enter fullscreen mode Exit fullscreen mode

The variable “city” had a perfect home with the namespace “user”. It’s very clear that “user.city” is the city belonging to the user. With the nested destructuring technique, you lose these benefits.


This overdestructuring can also lead to name clashes, which would require renaming the variable:

const { city } = location
const { user: { city: userCity }} = results
Enter fullscreen mode Exit fullscreen mode

“userCity” vs. “user.city”. Is this difference worth the added complexity and loss of intent?

Compare these two code statements that could follow the above example:

/*❌*/ if (city === userCity) {}
/*✔️*/ if (location.city === user.city) {}
Enter fullscreen mode Exit fullscreen mode

In multi-line statements, over-destructuring can also confuse the reader as to which side of the assignment the reader is currently on (left side or right side):

const {
  user: {
    city: userCity
  },
  location: {
    city: locationCity
  }
  ...rest
} = {
  ...cache,
  user: await getUser()
  date: now()
}
Enter fullscreen mode Exit fullscreen mode

Not enough? How about some inlined TypeScript types to mix things up:

const {
  user: {
    city: userCity
  },
  location: {
    city: locationCity
  }
  ...rest
} = {
  ...cache,
  user: await getUser()
  date: now()
} : {
  user: {
    id: string;
    city: string
  }
  date: number,
  location: {
    id: string;
    city: string;
  }
}
Enter fullscreen mode Exit fullscreen mode

Namespaces are just fine. In fact, they are very helpful in communicating where a variable belongs to. And best of all, you get all of it out of the box.


This was an excerpt from my e-book Intent-Driven Development which will teach you how to simplify the day-to-day code you run into and the balance between over- and under-engineering. Get it over at https://michaelzanggl.com/intent.

Latest comments (0)