Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't filter a type out of an array of unions #6035

Closed
ghost opened this issue Mar 25, 2018 · 10 comments
Closed

Can't filter a type out of an array of unions #6035

ghost opened this issue Mar 25, 2018 · 10 comments

Comments

@ghost
Copy link

ghost commented Mar 25, 2018

try flow

const foo: Array<string | number> = [];
const bar = foo.filter(n => typeof n === 'string');

bar is still Array<string | number>

I also can't annotate bar to Array<string> without casting it through any first

@TrySound
Copy link
Contributor

TrySound commented Mar 25, 2018

It's known problem. You can find a lot of issues about this.

As a solution you can use reduce or flatMap which can be refined with actual values instead of magical booleans.

@ghost
Copy link
Author

ghost commented Mar 26, 2018

@TrySound - I don't see how either reduce or flatMap is a replacement for filter. Can you give an example?

@TrySound
Copy link
Contributor

Sorry, "or".

reduce from array prototype

const a = b.reduce((acc, d) => {
  if (typeof d === 'number') {
    acc.push(d);
  }
  return acc;
}, [])

or flatMap from any library or handwritten or from the future

const a = flatMap(b, d => typeof d === 'number' ? [d] : []);

they are both easy to type.

@TrySound
Copy link
Contributor

TrySound commented Mar 26, 2018

Performance impact with flatMap doesn't matter if you don't work with large arrays.

@ghost
Copy link
Author

ghost commented Mar 26, 2018

Performance impact with flatMap doesn't matter if you don't work with large arrays.

Like canvas pixel arrays? :) I think I'll just cast through any for now, as much as I hate doing that

@TrySound
Copy link
Contributor

@markkahn Then reduce as more common version of filter will solve your problem. Just don't use filter if you need refinement.

@ghost
Copy link
Author

ghost commented Mar 26, 2018

What's your reasoning for pushing towards something like reduce vs. casting through any?

const bar: Array<string> = (foo.filter(n => typeof n === 'string'): any);

.filter has a clear meaning, I feel like reduce is being used way outside of it's normal intention here.

@ghost
Copy link
Author

ghost commented Mar 26, 2018

Dupe of #1414

@ghost ghost closed this as completed Mar 26, 2018
@TrySound
Copy link
Contributor

any is not safe.

@ghost
Copy link
Author

ghost commented Mar 26, 2018

of course not, one of its purposes is to bypass the typechecker in exactly situations like this where it fails. Perhaps it's just philosophical, but I'd rather keep the intent of my code correct than jump through weird coding patterns to make flow happy.

Though I see your point, and I'd argue for something like this instead:

const filteredAry = [];
ary.forEach(v => (typeof v === 'string') && filteredAry.push(v));

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant