6 ms·
In addition to being essentially a combined "filter" and "map", it's also a "better" filter than filter itself in TypeScript in such that it narrows types much
by jasonkillian 5y ago
In addition to being essentially a combined "filter" and "map", it's also a "better" filter than filter itself in TypeScript in such that it narrows types much more ergonomically[0].
In TypeScript, you might have an array of multiple types (e.g. `Array<A | B>`), and use a `filter` call to only keep the `A`s. However, in many situations TypeScript can't figure this out and the resulting array type is still `Array<A | B>`. However, when you just use `flatMap` to do nothing more than filtering in the same way, TypeScript can determine that the resulting type is just `Array<A>`. It's a bit unfortunate really - `filter` is faster and more readable, but the ergonomics of `flatMap` type-wise are so much nicer! Just some interesting trivia.
[0]: https://github.com/microsoft/TypeScript/issues/16069#issuecomment-730710964 https://github.com/microsoft/TypeScript/issues/16069#issueco...
- amitport 5y agoI wonder if it is possible to add a feature to Typescript to help with this: You could potentially add a syntax for type guards function types, then add a signature to filter that accepts a type guard and returns an array of the guarded types. Shouldn't be too much of a stretch given that we have type guards. The syntax is a bit annoying... should be something like filter<A, B>(cb: A => A is B) :/
- abrioy 5y agoYou can use a type guard[1] as an argument to Array.filter, but the function has to be explicitly typed as such. I don't know why the type isn't narrowed in Array.filter like it is in if statements without this weird workaround. const array: (number | string)[] = []; const mixedArray = array.filter(value => typeof value === 'string'); // mixedArray: (number | string)[] const arrayOfString = array.filter((value): value is string => typeof value === 'string'); // arrayOfString: string[] This example in Typescript playground: https://www.typescriptlang.org/play?#code/MYewdgzgLgBAhgJwXAngLhgCjAVwLYBGApgjAD4zQICWYA5gJQDaAujALwysDcAUL6Eiw81AB5EAJgEEkqDvFkoAdADNqAGyglMANzjqcRDgD4YUFAAciIFTD0Gj7JzADkVWnRcM+Aeh8wRcWlFDGx8YlIKd3pmFgFwaAVkFAB5FQBlKBp6eURk1Q0tBExdfUMGDHtDGGoISiyPEzNLa1sqx2c3BvovX3881DTM7LoMaLpWIA https://www.typescriptlang.org/play?#code/MYewdgzgLgBAhgJwXA... [1]: https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types https://www.typescriptlang.org/docs/handbook/advanced-types....
- amitport 5y agoOh so there is an overload! filter<U extends T>(pred: (a: T) => a is U): U[]; Additionally, getting TS better at inferring type guards is an open issue (literally): https://github.com/microsoft/TypeScript/issues/38390 https://github.com/microsoft/TypeScript/issues/38390