Skip to content
goodguydaniel.com

Destructuring in JavaScript: the not so good parts

JavaScript2 min read

Generally speaking, I would say everybody loves the destructuring assignment, and for good reasons. Next, I list some of the amazing things one can achieve with destructuring in JavaScript.

Object destructuring

1const user = { username: "captain", email: "captain@email.com", age: 30 };
2const { username, age } = user;

Provide default values

1const user = { email: "captain@email.com", age: 30 };
2const { username = "unknown", age } = user;
3// you can now use username with value 'unknown'

Renaming variables on creation

1const user = { username: "captain", email: "captain@email.com", age: 30 };
2const { username, age: userAge } = user;
3// you know have age value 30 in the variable userAge

Nested object destructuring ⚠️

1const user = { username: "captain", age: { value: 30, label: "30 years old" } };
2const {
3 username,
4 age: { label },
5} = user;
6// you can now use label directly

Array destructuring

1const rgb = [200, 255, 100];
2const [red, green, blue] = rgb;
3// the variables red, green and blue match the elements order in rgb array

Works with any iterable on the right-side (e.g Set)

1let [a, b, c] = "abc"; // ["a", "b", "c"]
2let [one, two, three] = new Set([1, 2, 3]);

Swapping Variables

1let a = 1;
2let b = 2;
3[b, a] = [a, b];

Swapping array positions

1const arr = [1, 3, 2, 4, 5];
2[arr[1], arr[2]] = [arr[2], arr[1]];
3// arr is now [1, 2, 3, 4, 5]

Skipping items ⚠️

1const rgb = [200, 255, 100];
2// skip the first two items
3// assign the only third item to the blue variable
4const [, , blue] = rgb;

Nested array destructuring ⚠️

1const color = ["#FF00FF", [255, 0, 255], "rgb(255, 0, 255)"];
2// use nested destructuring to assign red, green and blue
3const [hex, [red, green, blue]] = color;
4console.log(hex, red, green, blue); // #FF00FF 255 0 255

Function parameter destructuring ⚠️

1function getUserInfo({ username, email }) {
2 return `Username: ${username}; Email: ${email}`;
3}
4const user = { username: "captain", email: "captain@email.com" };
5const userInfo = getUserInfo(user);


What's not so good here

The most significant dilemma of destructuring it's related with the fact that relies on properties of nested structures that can only be evaluated at runtime, let me give you an example.

1function addEmailToList(list, { email }) {
2 if (email) {
3 list.push(email);
4 }
5}
6const list = ["a@mail.com", "b@mail.com"];
7const user = undefined;
8
9addEmailToList(list, user);
10// Uncaught TypeError: Cannot destructure property `email` of 'undefined' or 'null'

On the other hand, if you write this without destructuring, you won't make assumptions on the user, you can double check whether the given user is valid.

1function addEmailToList(list, user) {
2 if (user && user.email) {
3 list.push(user.email);
4 }
5}
6const list = ["a@mail.com", "b@mail.com"];
7const user = undefined;
8
9addEmailToList(list, user);

null - a catastrophe waiting to happen

Just a note, for you to be conscious that as in default assignment default parameters the null value it's not considered false, thus you can't fall back to some default value in destructuring a property whose value is null.

1function formatAddress(info) {
2 const { country = "-", city = "-" } = info;
3 return `${country}, ${city}`;
4}
5
6const info = { country: "Portugal", city: null };
7const result = formatAddress(info);
8// "Portugal, null" it's what you get instead of "Portugal, -"

Every feature above mentioned exists for you to use, but we should find a balance (as in everything else in life). Below I list a few guidelines/rules that will help you find the balance when using destructuring.

cat kong fu balance

source: https://imgflip.com/tag/fat+cat+balance

The 3 Golden Rules

You might have noticed some previous warning sings (⚠️) in some of the listed usages of destructuring. I left those signs there because I consider those use cases potentially harmful.

  1. Don't use nested destructuring on data that comes from any external data sources (such as REST APIs, GraphQL endpoints or files). You never know when these APIs change their data contracts. Hopefully all of this it's synced between teams, but sometimes we get lost on the tiny details such as that one small property in some nested object that got renamed and instead of using snake_case it uses now camelCase just because it made more sense from an aesthetic point of view. Now your marvelous single page application is burning and falling into pieces because you were unsafely accessing this property when you could have protected yourself against it.
  2. Don't use nested destructuring on function arguments that have long or complicated signatures. It makes it super hard to understand what the actually API of the function is, and you might get breaking behavior because someone decided to use your function, but in some edge case they do not provide you the valid input for you to destruct upon.
  3. Don't use destructuring to retrieve a value if you rely on order. I listed the possibility of skipping elements with destructuring, it might sound tempting, but you might end up again breaking your website because your simple routine relies on the access of the Nth element of some inputted array. Also, you can still retrieve data out of the array, but it might be that in that position you don't get what you were expecting. If you choose this path, at this point, it should also be arguable that there's something very wrong either with your code or with the data model from where you're your reading data, use this one with care.

References

If you liked this article, consider sharing (tweeting) it to your followers.