Doing more complex conditional logic, getting more than two different values

Here’s how to get stuff with JavaScript.

This is basic, but Boolean logic can handle two values: true and false, or... potato or not potato. Then you can do stuff with it:

import DefaultIcon from './icons/Default'
import SpecialIcon from './icons/Special'
 
const hasDefaultIcon = true
const Icon = hasDefaultIcon ? DefaultIcon : SpecialIcon

But what if the value can be more than two things? This post is about that.

The demo code

Let’s say we get an array from an API: ['club', 'diamond', 'heart', 'spade'], and our task is to render playing cards, like so:

Let’s make a helper function called getSuit that gets us the right icon, which in this case is an SVG wrapped to a React component.

The above cards were rendered by the following code (getter highlighted):

<CardWrap>
  {suits.map(suit => {
    const Icon = getSuit(suit)
 
    return (
      <PlayingCard>
        <Icon width={30} />
      </PlayingCard>
    )
  })}
</CardWrap>

Loads of if else statements

One way of implementing the icon getter helper is with a chain of if else conditions:

const getSuit = suit => {
  if (suit === 'club') {
    return ClubsIcon
  } else if (suit === 'diamond') {
    return DiamondsIcon
  } else if (suit === 'heart') {
    return HeartsIcon
  } else if (suit === 'spade') {
    return SpadesIcon
  } else {
    return null
  }
}

That mess just doesn’t spark joy. I’ve completely stopped using the if else.

Loads of if statements

Somehow I find these if statements extremely simple and super readable:

const getSuit = suit => {
  if (suit === 'club') return ClubsIcon
  if (suit === 'diamond') return DiamondsIcon
  if (suit === 'heart') return HeartsIcon
  if (suit === 'spade') return SpadesIcon
 
  return null
}

There’s very little guesswork on how that works.

The switch case

Switch cases were basically made for this:

const getSuit = suit => {
  switch (suit) {
    case 'club':
      return ClubsIcon
    case 'diamond':
      return DiamondsIcon
    case 'heart':
      return HeartsIcon
    case 'spade':
      return SpadesIcon
    default:
      return null
  }
}

Loads of keywords are flying around. There is no need for break in a case when returning something.

Nested ternary condition

Nested ternaries work but are cryptic IMO:

const getSuit = suit => {
  return suit === 'club'
    ? ClubsIcon
    : suit === 'diamond'
      ? DiamondsIcon
      : suit === 'heart'
        ? HeartsIcon
        : suit === 'spade'
          ? SpadesIcon
          : null
}

Just an Object

Probably my favorite method of getting values is to just store them into an object, like so:

const suiteIcons = {
  club: ClubsIcon,
  diamond: DiamondsIcon,
  heart: HeartsIcon,
  spade: SpadesIcon,
}

The object key is the name, as usual. Then access the object’s properties with bracket notation when you need them:

<CardWrap>
  {suits.map(suit => {
    const Icon = suiteIcons[suit] || null
 
    return (
      <PlayingCard>
        <Icon width={30} />
      </PlayingCard>
    )
  })}
</CardWrap>

Note about the fallback: suiteIcons.potato is undefined, not null, and React will crash if it’s not handled.

You can also do shenanigans like this, bake it all into one thing:

const Icon =
  {
    club: ClubsIcon,
    diamond: DiamondsIcon,
    heart: HeartsIcon,
    spade: SpadesIcon,
  }[suit] || null

Conclusions

Maybe you had already used that object method without realizing it. I know I had. It was nice to articulate this in a post. I also find myself becoming disillusioned about else if.