在我的Flow注释JavaScript代码的某处,我有一个使用可空字段obj
定义的对象field
。
let obj: { field: ?number } = { field: 1 };
我有一个函数func
接受参数arg
,其结构与obj
相同,但 field
应非 - 可以此时。
function func(arg: {field: number}){
// do something
}
在检查func
不是obj
或obj.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]
两个问题:
上面的代码片段是用于演示问题的代码的简化版本。实际obj
更复杂。
答案 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;
}
这实际上会使arg.field
只写,这很好,因为写一个数字到field
总是安全的,但读从长远来看,一个是不安全的。
使它运作的最佳做法是什么?
这取决于您的真实代码在某种程度上的作用。在这个具体的例子中,我说直接将数字作为参数传递,但假设它需要是一个对象,你可以考虑创建一个只有func
需要的属性的新对象。