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

Filtering null values from an array of maybe types fails to produce an array of non-optional values #2846

Closed
Firehed opened this issue Nov 18, 2016 · 4 comments

Comments

@Firehed
Copy link

Firehed commented Nov 18, 2016

Per the title: if you have an array of maybe types, and filter out null values from that array (e.g. .map(val => val != null), flow fails to detect the "unwrapping" of these values and keeps treating the array as one of maybes. As a result, totally valid and safe future operations emit errors during typechecking.

// @flow

// Problem concept
let maybes: Array<?number> = [1,2,3];
let actuals = maybes
  .filter(val => val != null) // Should now be Array<number>, but stays as Array<?number>
  .filter(val => val > 0);

// Discovered this way
type Story = {id: number};
let story_ids = [1, 2, 3];
let stories: Array<Story> = [{id: 2}, {id: 3}];
let example = story_ids 
  .map(id => stories.find(story => story.id === id))
  .filter(story => story != null)
  .filter(story => story.id > 2)

// Works
let works = story_ids
  .map(id => stories.find(story => story.id === id))
  .filter(story => story != null && story.id > 2)
  // all future operations require the null check as well
src/example.js:7
  7:   .filter(val => val > 0);
                      ^^^ null. This type cannot be compared to
  7:   .filter(val => val > 0);
                            ^ number

src/example.js:7
  7:   .filter(val => val > 0);
                      ^^^ undefined. This type cannot be compared to
  7:   .filter(val => val > 0);
                            ^ number

src/example.js:16
 16:   .filter(story => story.id > 2)
                              ^^ property `id`. Property cannot be accessed on possibly undefined value
 16:   .filter(story => story.id > 2)
                        ^^^^^ undefined

Poking around, it looks like this should work, but it's at best unclear how to get flow to pick up on this.

@gcanti
Copy link

gcanti commented Nov 19, 2016

let maybes: Array<?number> = [1,2,3]
let actuals = maybes
  .filter(Boolean)
  .filter(val => val > 0)

@vkurchatkin
Copy link
Contributor

See: #1414

@eluchsinger
Copy link

@gcanti Does that work only for non falsy values?

@rszymula
Copy link

rszymula commented Sep 2, 2020

@Firehed @vkurchatkin can we reopen this? The solution accepted is too specific
like @eluchsinger is asking
@gcanti

This is only works for the specific case that the array is full of numbers

let maybes: Array<?number> = [1,2,3]
let actuals = maybes
.filter(Boolean)
.filter(val => val > 0)

what if I have
{
person: {
place: ?string
}
}

and I filter out all non null places?

or what if I want to do a mapping afterwards?

let actuals = maybes
.filter(Boolean)
.filter(val => val > 0)
.map(item => item + 5)

What now? How to fix flow in the general case?

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

No branches or pull requests

5 participants