考虑以下代码片段,我有两种对象类型。第二种类型是第一种类型的更精炼版本:
/* @flow */
type A = {|
value: string | number,
|}
type B = {|
value: number,
|}
const b:B = { value: 2 };
const a:A = { value: 2 }; //works.
const z:A = b; //fails, but for javascript it is exactly the same as line above
这在最后一行失败,因为flow告诉我“number”与“string”不兼容。但是类型是“联合”而不是交集,所以它应该工作吗? (只是再次使用该类型,我必须再次改进它)。
在我的实际代码中,我实际上有所述对象的数组,并且对象包含更多数据,因此手动复制对象不是可行的方法。
我意识到这是一个抽象概述,但最后我希望有一个函数,它采用“精制A”并返回“A”,即一个更真实的例子:
type A = {|
value: string | number,
value2: string,
|}
function foo(input: $ReadOnlyArray<{| ...$Exact<A>, value: number|}>): Array<A> {
return input.filter(v => v.value === 2);
}
有没有更好的方式来说“这个函数需要X的精炼版本”。
文档的Depth Subtyping页面中的最后一段解释了这里发生了什么(文件肯定有点糟糕)。
默认情况下,对象属性是不变的,它允许读取和写入,但在它们接受的值中更具限制性。
现在value
上的A
属性默认是不变的。这意味着它只接受其给定的类型,非常具体。你不能指定它是number
或string
的东西,你只能指定它是number | string
的东西。任何具有明显比number | string
明确的类型的东西都不会被接受:
type Ambiguous = {|
value: string | number,
|};
type Specific = {|
value: number,
|};
const myAmbiguous: Ambiguous = ({ value: 1 }: Specific); // error!
我们可以做的一件事就是将该属性标记为协变,如前面同一段所述:
加号表示[...]属性是“协变的”。使用协变属性允许我们使用具有该属性的子类型兼容值的对象。
这应该允许我们为我们的属性分配一个更具体的类型(在本例中为number
):
type Ambiguous = {|
+value: string | number,
|};
type Specific = {|
value: number,
|};
const myAmbiguous: Ambiguous = ({ value: 1 }: Specific); // all good
但请注意,value
现在是只读的:
myAmbiguous.value = 3; // error!
// ^ Cannot assign `3` to `myAmbiguous.value`
// because property `value` is not writable.
我建议阅读Depth Subtyping页面的其余部分以及Type Variance上的页面。
这是两种不同的类型,流量不允许分配。
你的2行不一样 - 第一行创建一个A类型的对象并分配它 - 第二行想要将类型B的对象分配给类型A的变量