DEV Community

Jade Banks
Jade Banks

Posted on

Why Truthy Checks can Break on Zero in TypeScript

JavaScript/TypeScript can treat non-boolean values as booleans in certain situations. Basically, there are a set of values which are defined as Falsy. All other values are considered Truthy.

When combined with Optional Properties, code can be more concise and easier to read.

Consider a system for filtering numerical values where each filter property is optional.

type FilterOptions = {
  greaterThan?: number,
  lessThan?: number,
};

/* Returns true if `value` satisfies the filter, false otherwise */
function isInFilter(value: number, filter: FilterOptions): boolean {
  if (filter.greaterThan && value <= filter.greaterThan)
    return false;

  if (filter.lessThan && value >= filter.lessThan)
    return false;

  return true;
}

/*
  Demonstrates the filtering function by logging
  the numbers between -5 and 5 that satisfy the filter
*/
function filterExample(filter: FilterOptions) {
    const results:number[] = [];

    for (let i = -5; i <= 5; i++)
      if (isInFilter(i, filter))
        results.push(i);

    console.log(results.join(','));
}

// No filtering
// Output: -5,-4,-3,-2,-1,0,1,2,3,4,5
filterExample({});

// Numbers above 2
// Output: 3,4,5
filterExample({
    greaterThan: 2,
});
Enter fullscreen mode Exit fullscreen mode

This works fine, with and without the greaterThan property.

However if we apply the following, it will fail

// This fails
// Expected Output: "1,2,3,4,5"
// Actual Output: "-5,-4,-3,-2,-1,0,1,2,3,4,5"
filterExample({
    greaterThan: 0,
});
Enter fullscreen mode Exit fullscreen mode

The bug is in this line

   if (filter.greaterThan && value <= filter.greaterThan)
     return false;
Enter fullscreen mode Exit fullscreen mode

When filter.greaterThan is 0, it is considered falsy in the same way undefined is. So it behaves as if that filter property wasn't set.

The fix is to change the line to the following

   if (filter.greaterThan !== undefined && value <= filter.greaterThan)
     return false;
Enter fullscreen mode Exit fullscreen mode

Same fix would be needed for the lessThan property.

Final Thoughts

When treating non-boolean values as booleans, make sure you've considered all the possible Falsy values that could apply in your application. The same issue could occur for an empty string "" or NaN for example.

If a value can be undefined or null, you'd need something like the following

    if (filter.greaterThan !== undefined && filter.greaterThan !== null && ...)
Enter fullscreen mode Exit fullscreen mode

or

    // Note: single `=` to apply loose equality
    if (filter.greaterThan != undefined && ...
Enter fullscreen mode Exit fullscreen mode

You can play around with this code in this Playground

Top comments (0)