DEV Community

Cover image for The filter(Boolean) trick
Michael Uloth
Michael Uloth

Posted on • Originally published at michaeluloth.com on

The filter(Boolean) trick

Here’s a trick I often find helpful.

Bad array. Very, very bad.

You have an array of whatever:

const array = [{ stuff }, { moreStuff }, ...]
Enter fullscreen mode Exit fullscreen mode

But hiding in that array are some unusable null or undefined values:

const array = [{ good }, null, { great }, undefined]
Enter fullscreen mode Exit fullscreen mode

Those empty values might be a sneaky little gift from your API. Or you may have left them there yourself while validating the original data. Either way, you’ve got a problem.

Looping over null data

If you try to perform actions on every item in the array, you’ll run into errors when you hit those null and undefined items:

const newArray = array.map(item => {
  // Of course this will work, wheeee...
  const assumption = item.thing
})

// Oh noooo...
🚨 Cannot read property "thing" of undefined. 🚨
🚨 Cannot read property "thing" of null. 🚨
Enter fullscreen mode Exit fullscreen mode

Illegal! Now you’re a criminal. Before you interact with an item, you need to make sure it exists.

Null checks?

You could confirm each item exists by performing a null check before you use it:

const newArray = array.map(item => {
  // Life has made me cautious.
  if (!item) {
    return item // Just forget it
  }

  // If we get this far, item exists.
  const assumption = item.thing
})
Enter fullscreen mode Exit fullscreen mode

Buuut, now your code is getting cluttered. And worse, those dangerous empty values will be passed along to newArray. So when newArray is used, another round of suspicious null checks will be needed.

The truth and only the truth

Want something better?

Here’s my favourite way to quickly remove all empty items from an array:

const array = [{ good }, null, { great }, undefined]

const truthyArray = array.filter(Boolean)
// truthyArray = [{ good }, { great }]
Enter fullscreen mode Exit fullscreen mode

The filter(Boolean) step does the following:

  1. Passes each item in the array to the Boolean() object
  2. The Boolean() object coerces each item to true or false depending on whether it’s truthy or falsy
  3. If the item is truthy, we keep it

Where did item go?

I love how concise filter(Boolean) is, but it might look strange that we aren’t explicitly passing item to Boolean.

The main thing to know is that, in JavaScript, this:

array.filter(item => Boolean(item))
Enter fullscreen mode Exit fullscreen mode

is exactly the same as this:

array.filter(Boolean)
Enter fullscreen mode Exit fullscreen mode

The second version is just written in a β€œtacit” or β€œpoint-free” style. We don’t name each item and pass it into Boolean, but JavaScript understands that Boolean takes one argument, so it takes the argument filter() exposes and passes it to Boolean for you.

If you find the first version easier to understand, use it! Writing readable code is more important than using fancy tricks.

Safer mapping

With our new tool, we can remove the null checks from above and chain a filtering step instead:

const newArray = array.filter(Boolean).map(item => {
  // Item is always truthy!
  const assumption = item.thing
})
Enter fullscreen mode Exit fullscreen mode

Now, our map can focus on what it’s trying to do, and we’ve removed the empty values from our pipeline forever.

Hope that helps!

Glossary

  • Falsy values: false, 0, -0, 0n, "", null, undefined, NaN
  • Truthy values: anything not in the falsy list

Links


Originally published at michaeluloth.com

Discussion (2)

Collapse
jsn1nj4 profile image
JSn1nj4β€β€πŸ‘¨β€πŸ’»

That is a really cool idea. I often forget about passing built-in functions and such as callbacks directly to these methods (and I don't think I thought of chaining array methods either for some reason yet).

Thanks for this!

Collapse
lifelongthinker profile image
Sebastian

One of those happy moments when you know: one thing less to hassle with in the future. Very much appreciated πŸ‘πŸ‘