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,
});
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,
});
The bug is in this line
if (filter.greaterThan && value <= filter.greaterThan)
return false;
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;
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 && ...)
or
// Note: single `=` to apply loose equality
if (filter.greaterThan != undefined && ...
You can play around with this code in this Playground
Top comments (0)