How to Conditionally Add to an Object or Array in JavaScript

amberleyjohanna

Amberley Romo

Posted on September 9, 2020

How to Conditionally Add to an Object or Array in JavaScript

In the course of my work, it's not uncommon that I need to conditionally add properties to objects, or (probably less commonly) values to arrays. Let's talk about how to do both. This is the piece of code I'll ultimately use as an example:

const trueCondition = true;
const falseCondition = false;

const obj = {
  ...(trueCondition && { dogs: "woof" }),
  ...(falseCondition && { cats: "meow" }),
};

// { dogs: 'woof' }

const arr = [
  ...(trueCondition ? ["dog"] : []),
  ...(falseCondition ? ["cat"] : [])
];

// ['dog']
Enter fullscreen mode Exit fullscreen mode

First, defining a few things.

If you're familiar with the && operator, the ternary operator, and spread syntax, skip ahead.

The logical && (AND) operator

&& is a logical operator. Logical operators are used to "reason" about Booleans. The && operator is one of three available in JavaScript (Not material here, but for completeness -- the two others are the || (OR) operator and ?? (nullish coalescing) operator.).

Usage

// expr1 && expr2

console.log(true && "hi");
// hi

console.log("abc" && "123");
// 123

console.log({} && "empty but valid");
// empty but valid

console.log(false && "bye");
// false
Enter fullscreen mode Exit fullscreen mode

If the first expression (on the left side) is truthy ("considered true when encountered in a Boolean context"), return the second expression (on the right side).

If the first expression is falsy ("considered false when encountered in a Boolean context"), return the first expression.

Short-circuit evaluation

The && expression is evaluated left to right. If the first expression is falsy, the full expression is short-circuit evaluated to the falsy expression (meaning the second expression is never evaluated). This is what lets us do things like safely access nested properties on an object:

const obj = {};

console.log(obj.first && obj.first.second);
// undefined

console.log(obj.first.second);
// TypeError: Cannot read property 'second' of undefined
Enter fullscreen mode Exit fullscreen mode

The conditional (ternary) operator

The ternary operator can be thought of as a shortcut for the if statement. It's made of of three parts:

  • A condition followed by a question mark (?)
  • An expression to execute if the condition is truthy, followed by a colon (:)
  • an expression to execute if the condition is falsy
// condition ? exprIfConditionTrue : exprIfConditionFalse
Enter fullscreen mode Exit fullscreen mode

An example. The two functions below accomplish the exact same thing using different syntax. The first uses if logic, and the second uses a ternary

/*
 * Example 1
 */

function getWelcomeMessage(isLoggedIn) {
  if (isLoggedIn) {
    return "Welcome!";
  } else {
    return "Please log in.";
  }
}

console.log(getWelcomeMessage(true));
// Welcome!

console.log(getWelcomeMessage(false));
// Please log in.

/*
 * Example 2
 */

function getWelcomeMessageTernary(isLoggedIn) {
  return isLoggedIn ? "Welcome!" : "Please log in.";
}

console.log(getWelcomeMessageTernary(true));
// Welcome!

console.log(getWelcomeMessageTernary(false));
// Please log in.
Enter fullscreen mode Exit fullscreen mode

The spread operator (...)

Spread syntax can be used to expand an iterable (like an array expression), or expand object properties.

Spreading an iterable:

let myDogs = [`Riggins`, `Lyla`];
let parentsDogs = [`Ellie`, `Remi`];

const holidayDoghouse = [...myDogs, ...parentsDogs];
// [ 'Riggins', 'Lyla', 'Ellie', 'Remi' ]
Enter fullscreen mode Exit fullscreen mode

Spreading object properties:

let existingAnimals = {
  dogs: 2,
  cats: 4,
  donkeys: 2,
  horses: 2,
};

let newAnimals = {
  goats: 2,
};

const allAnimals = {
  ...existingAnimals,
  ...newAnimals,
};
// { dogs: 2, cats: 4, donkeys: 2, horses: 2, goats: 2 }
Enter fullscreen mode Exit fullscreen mode

It can be used on iterables like an array or a string.
It expands an iterable to its individual elements

Conditionally add a property to an object

To conditionally add a property to an object, we can make use of the && operator.

const trueCondition = true;
const falseCondition = false;

const obj = {
  ...(trueCondition && { dogs: "woof" }),
  ...(falseCondition && { cats: "meow" }),
};

// { dogs: 'woof' }
Enter fullscreen mode Exit fullscreen mode

In the example above, in the first property definition on obj, the first expression (trueCondition) is true/truthy, so the second expression is returned, and then spread into the object.

In the second property definition, the first expression (falseCondition) is false/falsy, and so the first expression is returned (and the second expression is never evaluated, because of short-circuiting). It may seem a little confusing to spread a falsy expression, but the result is that it is ignored:

const spreadFalsy = {
  ...false,
  ...null,
  ...undefined,
};

console.log(spreadFalsy);
// {}
Enter fullscreen mode Exit fullscreen mode

You don't need parentheses in evaluating these expressions, but I prefer them, to make it clear that the spread operation applies to the result of the full expression.

const trueCondition = true;
const falseCondition = false;

const withParentheses = {
  ...(trueCondition && { dogs: "woof" }),
  ...(falseCondition && { cats: "meow" }),
};

// { dogs: 'woof' }

const withoutParentheses = {
  ...trueCondition && { birds: "tweet" },
  ...falseCondition && { foxes: "???" },
};

// { birds: 'tweet' }
Enter fullscreen mode Exit fullscreen mode

Conditionally add a value to an array

Conditionally adding a value to an array looks a little different. Rather than using an && operator, we use a ternary operator.

Unlike the object spread example, if you attempt to spread on a falsy value in an array, you'll get a TypeError:

const falseCondition = false;

const arr = [...(falseCondition && ["cat"])];
// TypeError: boolean false is not iterable
Enter fullscreen mode Exit fullscreen mode

Hence we need a ternary; Using a ternary, we can fall back to spreading an empty array. Then (assuming we've correctly provided two possible iterables) both possible returned expressions will be iterables:

const trueCondition = true;
const falseCondition = false;

const arr = [
  ...(trueCondition ? ["dog"] : []),
  ...(falseCondition ? ["cat"] : [])
];

// ['dog']
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
amberleyjohanna
Amberley Romo

Posted on September 9, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related