admin 管理员组

文章数量: 1086019

Say you have a couple of simple Flow types with optional properties:

type A = { b?: B };
type B = { action?: () => void };

And you want to access the properties in a chain and know they are defined:

a.b.action()

What's the idiomatic way to tell Flow that a.b and b.action are safe?

Say you have a couple of simple Flow types with optional properties:

type A = { b?: B };
type B = { action?: () => void };

And you want to access the properties in a chain and know they are defined:

a.b.action()

What's the idiomatic way to tell Flow that a.b and b.action are safe?

Share Improve this question asked Nov 22, 2016 at 22:47 ideide 20.9k6 gold badges71 silver badges112 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 8

There isn't a simple answer. You basically have three options.

  • Circumvent the typechecker, giving up type safety.
  • To maintain type safety do a runtime check. Flow understands many runtime checks and will refine types based on them.
  • Restructure your program so that these properties are not optional.

To circumvent the typechecker entirely and give up safety, you could do something like (a: any).b.action(). I don't remend this.

Obviously there is not enough information in this question to determine if it's feasible or even desirable to restructure your program to avoid having optional properties.

So, to maintain type safety you need to have a runtime check. You could do something like:

if (a.b != null && a.b.action != null) {
  a.b.action();
} else {
  // throw error or something
}

Or, if you simply want to assert that they are non-null, Flow has special-cased functions named invariant for that purpose (of course, you need to figure out how to get it at runtime. In Node, you can do import invariant from 'assert'. It's pretty simple to write yourself if you want, though).

invariant(a.b != null && a.b.action != null);
a.b.action();

The one caveat with this sort of thing is that Flow aggressively invalidates type refinements if it believes that something could have been changed. So, if there are any intervening function calls between the tests and the use, it could start erroring again. In that case, you'll have to pull each bit out into a separate variable, something like:

const b = a.b;
invariant(b != null);
const action = b.action;
invariant(action != null);
// other stuff that would have invalidated the type refinement
action();

You can test that they exist, like a.b && a.b.action && a.b.action()

https://flowtype/try/#0PQKgBAAgZgNg9gdzCYAoVAXAngBwKZgCCYAvGAN5gBGA-AFxgBCYAvgNya4HNmUCGAYwwBLOADt6YABQBKUgD4wANzjCAJqw6ooAVzFDRYsFCl8GhOeVRgwfAHRU7gkeNkcW6XfpdGA5qfNLa1sHMAAyMJDHZ0NwyPtog1cZdyA

This is the best way to do it.

export default function requireNotNull<T>(value: T, message?: string): $NonMaybeType<T> {
  if (value !== null && value !== undefined) return value;
  throw new Error(message || "Value is null or undefined");
}

本文标签:

Error[2]: Invalid argument supplied for foreach(), File: /www/wwwroot/roclinux.cn/tmp/view_template_quzhiwa_htm_read.htm, Line: 58
File: /www/wwwroot/roclinux.cn/tmp/route_read.php, Line: 205, include(/www/wwwroot/roclinux.cn/tmp/view_template_quzhiwa_htm_read.htm)
File: /www/wwwroot/roclinux.cn/tmp/index.inc.php, Line: 129, include(/www/wwwroot/roclinux.cn/tmp/route_read.php)
File: /www/wwwroot/roclinux.cn/index.php, Line: 29, include(/www/wwwroot/roclinux.cn/tmp/index.inc.php)