[英]Flow type refinement to non-nullable doesn't work
Somewhere in my Flow annotated JavaScript code I have an object obj
defined with nullable field field
.在我的 Flow 注释的 JavaScript 代码中的某个地方,我有一个对象
obj
定义为可空字段field
。
let obj: { field: ?number } = { field: 1 };
I have a function func
that accepts argument arg
which has the same structure as obj
but field
should be non-nullable at this time.我有一个函数
func
接受参数arg
,它与obj
具有相同的结构,但此时field
应该是不可为空的。
function func(arg: {field: number}){
// do something
}
I'm calling the func
with obj
after checking that the obj.field
is not null
or undefined
, hoping that Flow will do it's type refining magic and understand that obj.field
is always number
and it's type is OK to pass to the func
.在检查
obj.field
不是null
或undefined
之后,我正在用obj
调用func
,希望 Flow 会做它的类型精炼魔法并理解obj.field
总是number
并且它的类型可以传递给func
。
if(obj.field !== null && obj.field !== undefined){
func(obj);
}
Surprisingly getting an error, Flow doesn't like it:出人意料地得到一个错误,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 在试用流程中在线运行
Two questions:两个问题:
The code snippets above are simplified version of the code to demonstrate the problem.上面的代码片段是用于演示问题的代码的简化版本。 Actual
obj
is more complex.实际的
obj
更复杂。
First-off, Flow's refinement applies to individual fields here, but generally you aren't refining the whole object's type, so you can't refine an object's type based on refinement of a single field (as far as I'm aware).首先,Flow 的细化适用于此处的单个字段,但通常您不会细化整个对象的类型,因此您不能基于对单个字段的细化来细化对象的类型(据我所知)。 Even if you could, this example would still not be typesafe.
即使你可以,这个例子仍然不是类型安全的。 Here's something that illustrates the problem with allowing this:
以下内容说明了允许这样做的问题:
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);
}
Given purely the restrictions you're looking for, this would typecheck, but the value
inside the func
timeout callback would actually be null
.纯粹考虑到您正在寻找的限制,这将进行类型检查,但
func
timeout 回调中的value
实际上是null
。
The only way your given code could be safe with typechecking is if the arg.field
value were marked contravariant (note the -
in the property name for func
now, eg您给定的代码在类型检查时安全的唯一方法是
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 ) ( 在流尝试)
This effectively would make arg.field
write-only, which is fine because writing a number to field
would always be safe, but reading one is not safe in the long term.这将有效地使
arg.field
只写,这很好,因为将数字写入field
总是安全的,但从长远来看,读取一个数字并不安全。
What is best practice to make it work?
让它发挥作用的最佳实践是什么?
It depends on what your real code does, to some extent.在某种程度上,这取决于您的真实代码的作用。 In this specific example I'd say pass the number directly as the argument, but assuming it needs to be an object, you could consider creating a new object with just the properties
func
needs.在这个特定示例中,我会说直接将数字作为参数传递,但假设它需要是一个对象,您可以考虑创建一个仅具有
func
所需属性的新对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.