total-typescript / ts-reset

A 'CSS reset' for TypeScript, improving types for common JavaScript API's
https://www.totaltypescript.com/ts-reset
MIT License
7.74k stars 117 forks source link

Get tuple back from filter(Boolean) #182

Open Flammae opened 6 months ago

Flammae commented 6 months ago

Currently calling the filter(Boolean) method on a tuple turns it into an array of union:

let tuple = ["foo", undefined, "bar", 0] as const;
tuple.filter(Boolean) // ("foo" | "bar")[] 

We can enhance the function to instead return the filtered tuple:

interface ReadonlyArray<T> {
  filter(
    predicate: BooleanConstructor,
    thisArg?: any,
  ): FilterNonFalsy<this>;
}

type FilterNonFalsy<T> = T extends readonly [infer F, ...infer R]
  ? F extends false | 0 | "" | null | undefined | 0n
    ? FilterNonFalsy<R>
    : [F, ...FilterNonFalsy<R>]
  : [];

outputs:

(["1", "2", undefined] as const).filter(Boolean) // now: ["1" | "2"] prev: ("1" | "2")[]

([0, null, undefined, false, ""] as const).filter(Boolean) // now: [] prev: never[]

The order of values in a tuple will most definitely be maintained with this method