如何让 Flow 理解使用 lodash 进行运行时类型检查的动态代码?

How to make Flow understand dynamic code that uses lodash for runtime type-checking?

Flow 的 dynamic code example 表示 Flow 可以计算运行时类型检查:

function foo(x) {
  if (typeof x === 'string') {
    return x.length; // flow is smart enough to see this is safe
  } else {
    return x;
  }
}

var res = foo('Hello') + foo(42);

但在现实生活中,typeof 还不够好。我通常使用 lodash 的类型检查函数(_.isFunction_.isString 等),它可以处理很多边缘情况。

问题是,如果我们将示例更改为使用 lodash 进行运行时类型检查,Flow 将不再理解它:

function foo(x) {
  if (_.isString(x)) {
    return x.length; // warning: `length` property not found in Number
  } else {
    return x;
  }
}

var res = foo('Hello') + foo(42);

我试过使用 iflow-lodash,但似乎没有什么不同。

让 Flow 理解使用 lodash 进行运行时类型检查的代码的最佳解决方案是什么?顺便说一句,我是 Flow 的新手。

针对此特定案例最明显的解决方案是:

if (_.isString(x) && typeof x === 'string') {

一般来说,您可以通过抑制创意错误来克服 Flow 错误,如下所示:

if (_.isString(x)) {
  // @ManuallyTyped
  var xStr: string = x;
  return xStr.length;
} else { ... }

确保在您的流配置文件中将 // @ManuallyTyped 定义为自定义 suppress_comment 以使其正常工作。您可能需要一个丑陋的正则表达式,请参阅流程文档。

自从我上次这样做已经有一段时间了,但如果我没记错的话,Flow 会假设 你的 xStrstring,而其余的类型检查将正常工作。

这取决于你的 lodash libdefs 中的谓词类型。

谓词类型最近已添加到 Flow 中。尽管它们仍处于实验状态,所以我建议暂时谨慎使用它们。

function isString(x): boolean %checks { // << declare that the method is a refinement
  return typeof x === 'string';
}

function method(x: string | number): number {
  if (isString(x)) { // << valid refinement
    return x.charCodeAt(0); // << no errors
  } else {
    return x;
  }
}

[try it out]

Note: This answer may quickly fall out of date in one of the next releases as this is a brand new feature. Check out Flow's changelog for the latest information.

如果可能,目前的解决方案是使用the built-in refinements

function method(x: string | number): number {
  if (typeof x === "string") { // << Inline the check
    return x.charCodeAt(0);
  } else {
    return x;
  }
}