我们考虑以下代码片段,其中我有两种对象类型。第二种类型是第一种类型的更精致版本:
/* @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
这在最后一行失败,因为流程告诉我“数字”与“字符串”不兼容。但是类型是“并集”而不是交集,所以它应该有效吗? (只是为了再次使用该类型,我必须再次改进它)。
在我的真实代码中,我实际上拥有所述对象的数组,并且对象包含更多数据,因此手动复制对象并不是可行的方法。
<小时/>我意识到这是一个抽象的概述,但最终我希望有一个函数,它接受“精炼的 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 中的最后一段文档页面有点解释了这里发生的事情(无可否认,文档有点糟糕)。
By default, object properties are invariant, which allow both reads and writes, but are more restrictive in the values they accept.
现在,A
上的 value
属性默认情况下是不变的。这意味着它仅接受其给定类型,非常明确。您不能为其分配 number
或 string
的内容,只能为其分配 number | 的内容。字符串
。任何具有比 number | 或多或少明确的给定类型的东西字符串
不会被接受:
type Ambiguous = {|
value: string | number,
|};
type Specific = {|
value: number,
|};
const myAmbiguous: Ambiguous = ({ value: 1 }: Specific); // error!
对此我们可以做的一件事是将属性标记为协变,如同一段落中前面提到的:
The plus sign indicates that the [...] property is “covariant.” Using a covariant property allows us to use objects which have subtype-compatible values for that property.
这应该允许我们为我们的属性分配更具体的类型(在本例中为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.
我建议您阅读有关深度子类型的页面的其余部分以及 Type Variance 上的页面。 .
关于javascript - 流程中的未细化类型转换,在对象(以及所述对象的数组)中使用嵌套类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55314515/