Conditionally adding entries inside Array and object literals

[2017-04-28] dev, javascript, esnext, pattern
(Ad, please don’t block)

This blog post shows how you can conditionally add elements inside Array literals and properties inside object literals.

Conditionally adding elements inside Array literals  

The following code shows how a boolean cond determines whether or not the element 'a' is added to the Array arr.

const cond = false;
const arr = [
  ...(cond ? ['a'] : []),
  'b',
];
    // ['b']

This trick works, because the spread operator (...) for Array literals does nothing if its operand is an empty Array:

> [...[], 'a']
[ 'a' ]

Conditionally adding properties inside object literals  

You can use the proposed spread operator for properties in the same manner. Again, a boolean cond determines whether the property a is added to the object obj:

const cond = false;
const obj = {
  ...(cond ? {a: 1} : {}),
  b: 2,
};
    // {b: 2}

The spread operator for object literals does nothing if its operand is an object without enumerable own properties:

> {...{}, a: 1}
{ a: 1 }

Is it worth it?  

Using the spread operator in this manner leads to slightly cryptic code. Here it is again, for ease of reference:

const arr = [
  ...(cond ? ['a'] : []),
  'b',
];

The crypticity can be worth it if you want to create the Array with a single expression.

Different approaches  

Less cryptic would be to create the Array with the unconditional elements first and to then conditionally insert elements, via slice(). But that leads to error-prone code, because you have to manage indices properly (insert the last one of multiple elements first, etc.).

An elegant and self-descriptive solution is to use push() to construct the Array:

const arr = [];
if (cond) {
    arr.push('a');
}
arr.push('b');

Variations of the original approach  

A variation of the original approach is to use spread and a helper function:

const arr = [
  ...insertIf(cond, 'a'),
  'b',
];
function insertIf(condition, ...elements) { // (A)
    return condition ? elements : [];
}

In line A, the triple dots are the rest operator which collects the remaining arguments in an Array and assigns it to elements.

Another alternative is to conditionally insert either elements or undefineds and to then filter the latter values out:

const arr = [
  (cond ? 'a' : undefined),
  'b',
].filter(x => x !== undefined);

Further reading