在流中取消细化,在对象(和所述对象的数组)中嵌套类型

问题描述 投票:0回答:2

考虑以下代码片段,我有两种对象类型。第二种类型是第一种类型的更精炼版本:

/* @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的精炼版本”。

javascript flowtype
2个回答
1
投票

文档的Depth Subtyping页面中的最后一段解释了这里发生了什么(文件肯定有点糟糕)。

默认情况下,对象属性是不变的,它允许读取和写入,但在它们接受的值中更具限制性。

现在value上的A属性默认是不变的。这意味着它只接受其给定的类型,非常具体。你不能指定它是numberstring的东西,你只能指定它是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上的页面。


0
投票

这是两种不同的类型,流量不允许分配。

你的2行不一样 - 第一行创建一个A类型的对象并分配它 - 第二行想要将类型B的对象分配给类型A的变量

© www.soinside.com 2019 - 2024. All rights reserved.