我有这段代码:
function myFunction({x}: {x?: number} = {}) {
console.log(x);
return 'foo';
}
function wrapper({x}: {x: number}) {
return myFunction({x});
}
function myFunction2({x}: {x?: number} = {}) {
console.log(x);
return 'foo';
}
function wrapper2(args: {x: number}) {
return myFunction2(args);
}
myFunction
和wrapper
与myFunction2
和wrapper2
完全相同,对吧?但是Flow认为后一个副本中存在错误(live demo):
16: return myFunction2(args);
^ object type. This type is incompatible with the expected param type of
10: function myFunction2({x}: {x?: number} = {}) {
^ object type
这是一个错误,还是我遗漏了一些东西,这两个例子不相同?
答案 0 :(得分:1)
这是一个较小的例子,说明了同样的问题:
function myFunction({x}: {x?: number} = {}) {
console.log(x);
return 'foo';
}
const x: number = 5;
const obj: {x: number} = {x};
myFunction({x});
myFunction(obj);
(tryflow)
在第二个函数调用中,Flow发出此错误:
10: myFunction(obj);
^ object type. This type is incompatible with the expected param type of
1: function myFunction({x}: {x?: number} = {}) {
^ object type
这种情况发生的原因与解构无关。它只是因为对象是可变的,所以如果它们是不可变的,那么子类型规则并不像你期望的那样适用。
当对myFunction
的调用进行类型检查时,Flow只查看类型签名,而不是实现。因此,就Flow而言,myFunction
可以获取传递它的可变对象,并将其x
属性设置为null
。如果调用者认为x
属性绝不能是null
,则会违反其假设。
在第一个函数调用中,我们构造了一个全新的对象,因此Flow可以安全地推断出它具有类型{x?: number}
,因为它知道没有其他人持有对它的引用。