Conditionally adding keys to JavaScript objects using spread operators and short-circuit evaluation

The story of something I learned today

Today I needed to create a JavaScript object to pass to MongoDB, based on some request query parameters.

However, not all of the query parameters would be present all of the time.

To deal with this previously, I’ve written code that resembles this:

const buildAnObjectFromAQuery = (query) => {
const object = {};
  if (query.foo) {
object.foo = query.foo;
}
  if (query.bar) {
object.bar = query.bar;
}
  return object;
}

As you can imagine, this can get pretty hefty pretty quickly.

Today I learned, thanks to this Stack Overflow answer, that there is a better way, using spread operators and short-circuit evaluation. These are two things I’ve used a lot before, but never together in this way.

const buildAnObjectFromAQuery = query => ({
...query.foo && { foo: query.foo },
...query.bar && { bar: query.bar },
});

What’s going on there then?

In JavaScript, expressions using the && and || operators get checked for possible short-circuit evaluation:

  • && will only evaluate to true if both conditions are truthy. If the first one if falsey, then the second condition won’t even get evaluated.
  • Similarly, || will only evaluate to false if both condition is falsey. If the first condition is truthy, the second won’t get evaluated.

Additionally, in JavaScript, the && and || operators actually return the value of the last expression that gets evaluated in the statement.

In the above example, query.foo && { foo: query.foo } will return { foo: query.foo } if query.foo is truthy, and will short-circuit to return false if query.foo is falsey.

The returned value then gets spread into the object that is being returned by the function. If the expression returns false then nothing gets spread, and no new keys are added to the object.

In the example above, it also allowed me to get rid of all of the if statements, the object mutations, and allowed me to use ES2015’s implicit return, all of which I think makes the code much cleaner.

And that is something that I learned today.