对非可空的流类型细化不起作用

时间:2018-02-18 16:53:52

标签: javascript static-analysis flowtype

在我的Flow注释JavaScript代码的某处,我有一个使用可空字段obj定义的对象field

let obj: { field: ?number } = { field: 1 };

我有一个函数func接受参数arg,其结构与obj 相同,但 field非 - 可以此时。

function func(arg: {field: number}){
    // do something
}

在检查func不是objobj.field后,我正在使用null调用undefined,希望Flow会这样做类型精炼魔术,并了解obj.field总是number,并且它的类型可以传递给func

if(obj.field !== null && obj.field !== undefined){
    func(obj);
}

出乎意料地收到错误,Flow不喜欢它:

14:   func(obj);
           ^ Cannot call `func` with `obj` bound to `arg` because null or undefined [1] is incompatible with number [2] in property `field`.
References:
4:   field: ?number            ^ [1]
9: function func(arg: {field: number}){
                              ^ [2]

Run online in the Try Flow

两个问题:

  1. 为什么不起作用?
  2. 使它成功的最佳做法是什么?
  3. 上面的代码片段是用于演示问题的代码的简化版本。实际obj更复杂。

1 个答案:

答案 0 :(得分:1)

首先,Flow的细化适用于此处的各个字段,但通常您不会改进整个对象的类型,因此您无法细化对象' s类型基于单个字段的细化(据我所知)。即使你可以,这个例子仍然不是类型安全的。以下是解释允许此问题的问题:

let obj: { field: ?number } = { field: 1 };

if(obj.field !== null && obj.field !== undefined){
    func(obj);

    obj.field = null;
}

function func(arg: {field: number}){
    setTimeout(() => {
      var value: number = arg.field;
    }, 10);
}

纯粹是您正在寻找的限制,这可能会出现问题,但value超时回调中的func实际上是null

使用类型检查确定给定代码的唯一方法是arg.field值被标记为逆变(请注意-的属性名称中的func,例如

let obj: { field: ?number } = { field: 1 };

if(obj.field !== null && obj.field !== undefined){
    func(obj);
}

function func(arg: {-field: number}){
  arg.field = 43;
}

On Flow Try

这实际上会使arg.field只写,这很好,因为一个数字到field总是安全的,但从长远来看,一个是不安全的。

  

使它运作的最佳做​​法是什么?

这取决于您的真实代码在某种程度上的作用。在这个具体的例子中,我说直接将数字作为参数传递,但假设它需要是一个对象,你可以考虑创建一个只有func需要的属性的新对象。