简洁地告诉Flow在属性访问链中可空属性不会为null的惯用方法是什么?

ide*_*ide 5 javascript flowtype

假设您有几个带有可选属性的简单Flow类型:

type A = { b?: B };
type B = { action?: () => void };
Run Code Online (Sandbox Code Playgroud)

并且您想要访问链中的属性并知道它们已定义:

a.b.action()
Run Code Online (Sandbox Code Playgroud)

什么是告诉Flow a.b并且b.action安全的惯用方法?

Nat*_*ote 6

没有一个简单的答案.你基本上有三个选择.

  • 绕过typechecker,放弃类型安全.
  • 要保持类型安全,请执行运行时检查.Flow了解许多运行时检查,并将根据它们优化类型.
  • 重构程序,使这些属性不是可选的.

为了完全规避类型检查并放弃安全,你可以做类似的事情(a: any).b.action().我不推荐这个.

显然,在这个问题中没有足够的信息来确定重构程序以避免具有可选属性是否可行或甚至是否可取.

因此,为了保持类型安全,您需要进行运行时检查.你可以这样做:

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

或者,如果你只是想断言它们是非空的,那么Flow有一个以此invariant为目的命名的特殊功能(当然,你需要弄清楚如何在运行时获得它.在Node中,你可以这样做import invariant from 'assert'.它很漂亮但是,如果你愿意,可以简单地写自己.

invariant(a.b != null && a.b.action != null);
a.b.action();
Run Code Online (Sandbox Code Playgroud)

对此类事情的一个警告是,如果Flow认为某些内容可能已被更改,那么Flow会主动使类型细化无效.因此,如果测试和使用之间存在任何中间函数调用,则可能再次开始出错.在这种情况下,您必须将每个位拉出一个单独的变量,例如:

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