TypeScript Type-safe Filter Boolean
Here's how to make a type-safe alternative to .filter(Boolean) in TypeScript.
Boolean Filter
In JavaScript, there's a nice little short-hand for filtering non-nulls. If I have a sparse array:
const arr = ['a', undefined, 'b', null, 'c']
I can get rid of the nulls like this:
arr.filter(Boolean).forEach(character => console.log(character.toUpperCase()))
And that will print:
"A"
"B"
"C"
This is because the Boolean
constructor is used as the callback and has these properties:
> Boolean(undefined)
false
> Boolean(null)
false
> Boolean('')
false
> Boolean('a')
true
TypeScript Boolean Filter
But in TypeScript, this does not type check. This code:
arr.filter(Boolean).forEach(character => console.log(character.toUpperCase()))
Will yield this error on the dot operator for character.toUpperCase()
:
'character' is possibly 'null'.(18047)
(parameter) character: string | null
It works. It just doesn't type check. We can tell TypeScript not to care, and it's happy:
arr.filter(Boolean).forEach(character => console.log((character as any).toUpperCase()))
That prints "A" "B" "C". But the solution is yucky.
Type-safe Filter Boolean
What we really need is the equivalent of .filter(Boolean)
, but type safe. We can get that with this custom function:
function isDefined<T>(value: T | null | undefined): value is NonNullable<T> {
return value !== null && value !== undefined
}
It uses that nice predicate to type narrow to NonNullable
.
Then, to use it:
arr.filter(isDefined).forEach(character => console.log(character.toUpperCase()))
It type checks and is equivalent to .filter(Boolean)
! You need a custom function now, but I guess that's the price to pay for TypeScript in this case.