#Potential TS narrowing bug?

18 messages · Page 1 of 1 (latest)

candid wind
#

hey all, considering filing an issue on GH about typescript not properly narrowing in this scenario:

let values = [undefined, 1, 2, 3, undefined]
// -> (undefined | number)[]

values = values.filter(Boolean)

// TS should now know that values cannot be undefined, and the type of values is number[]

Is this behavior intentional? It's frustrated me for the longest time that you have to manually cast the result of the filter call to, say, number[] for it to know it won't be undefined

mossy elk
#

it's normal

#

especially considering how the type system and this function works

#

imagine you have a string[], applying filter will returning you the same type as the source, so string[]
the type stayed the same, only some values got removed

#

@candid wind

#

filter doesn't narrow anything

candid wind
#

hmm

mossy elk
#

if you need narrowing, you need to use a type predicate

#

!hb type predicate

tribal minnowBOT
candid wind
#

maybe it should though in this specific case

mossy elk
candid wind
#

gotcha

mossy elk
#
const values = [undefined, 1, 2, 3, undefined];
const isNumber = (n: unknown): n is number => typeof n === "number";

const filtered = values.filter(isNumber);
clever harbor
#

A generic isDefined helper is also useful:

tribal minnowBOT
#
const isDefined = <T>(x: T | undefined): x is T => x !== undefined

const foos = [undefined, 1, 2, 3, undefined]
//    ^? - const foos: (number | undefined)[]

const bars = foos.filter(isDefined)
//    ^? - const bars: number[]
clever harbor
#

ts-reset actually makes .filter(Boolean) work as you expect, but I wouldn't really recommend it.

mossy elk
#

also, @candid wind , Boolean won't work to keep all numbers, since it will exclude 0 which is falsy