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

Maybe Type Refining fail in Array method(map/filter/...etc.) #5541

Closed
jetzhliu opened this issue Dec 20, 2017 · 9 comments
Closed

Maybe Type Refining fail in Array method(map/filter/...etc.) #5541

jetzhliu opened this issue Dec 20, 2017 · 9 comments

Comments

@jetzhliu
Copy link

code see also here in flow.org/try

// @flow
let a: ?Object = undefined
if (a) {
  Object.keys(a).filter(k => a[k])
}

It currently report error as follow:

4:   Object.keys(a).filter(k => a[k])
                                ^ computed property. Computed property/element cannot be accessed on possibly null value
4:   Object.keys(a).filter(k => a[k])
                                ^ null
4:   Object.keys(a).filter(k => a[k])
                                ^ computed property. Computed property/element cannot be accessed on possibly undefined value
4:   Object.keys(a).filter(k => a[k])
                                ^ undefined
@apsavin
Copy link
Contributor

apsavin commented Dec 20, 2017

Variable with Maybe type can be changed. You can use const to ensure flow that refinement will not be lost.

@jetzhliu
Copy link
Author

How about the following case? @apsavin
flow/try

// @flow
function test(a: ?Object) {
  return a ? Object.keys(a).filter(k => a[k]) : []
}

I don't want to add a const variable as const b = a, but it can fix this problem.☹

@jcready
Copy link
Contributor

jcready commented Dec 21, 2017

Function parameters can be overwritten just like in your first example. There is a .flowconfig option you can enable to have flow treat function parameters as constants which would also fix your problem.

@vicapow
Copy link
Contributor

vicapow commented Dec 24, 2017

@jcready Thanks for the info. Could you go into more detail for me and others following along why Flow doesn't maintain the refinement into the body of the function when there's no new assignment of null to a within it? I've seen folks report this a few times so having a solid explanation would be helpful. Additionally, if this is not a bug, should we close this issue?

function test(a: ?Object) {
  if (!a) {
    return null;
  }
  const keys = Object.keys(a);
  for (const k of keys) a[k]; // Works?
  // keys.filter(k => a[k]); // Flow errors?
}

@vicapow
Copy link
Contributor

vicapow commented Dec 24, 2017

Here's one more example that's a little confusing to myself.

function test(a: ?Object) {
  if (!a) {
    return null;
  }
  let b = a; // Magically, this fixes the issue but couldn't `b` just as well be overwritten?
  return Object.keys(b).filter(k => b[k]);
}

@jcready
Copy link
Contributor

jcready commented Dec 24, 2017

So I'm taking a guess here, but I believe the reason your last example works is because there can not be refinement invalidation of b because at the point b is declared it is typed as just Object, meaning it can never become null. The a function parameter on the other hand was typed as ?Object and then refined to be Object, but that refinement can be invalidated. The b variable's type did not need to be refined and therefore cannot be invalidated.

@jcready
Copy link
Contributor

jcready commented Dec 24, 2017

For example, this will throw the same error:

function test(a: ?Object) {
  let b: typeof a;
  if (!a) {
    return null;
  }
  b = a;
  return Object.keys(b).filter(k => b[k]);
}

@stereobooster
Copy link

in the latest flow this has no errors

@SamChou19815
Copy link
Contributor

no longer errors

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

6 participants