2017-09-01 75 views
0

我正在尝试使用流程0.53.1。你能帮我解释一下这个奇怪的行为吗?流程中的递归类型定义

此代码示例:

/* @flow */ 

type AnySupportedType = 
    | AnySupportedPrimitive 
    | AnySupportedObject 
    | AnySupportedArray; 
type AnySupportedArray = Array<AnySupportedType>; 
type AnySupportedObject = { [string]: AnySupportedType }; 
type AnySupportedPrimitive = boolean | number | string | void; 

type DataID = string 
type Data = { 
    id: DataID 
} 

const y: Data = { id: "123" } 
const x: AnySupportedType = y; 

呈现这样的错误:

17: const x: AnySupportedType = y; 
           ^object type. This type is incompatible with 
17: const x: AnySupportedType = y; 
      ^union: AnySupportedPrimitive | AnySupportedObject | AnySupportedArray 

Link到flow.org基于web的例子一起玩。

回答

0

答案是Flow有两种方法来输入对象。一,你AnySupportedObject,对待对象作为字典,你可以任意键(类似于Map<string, whatever>找到一个项目。

另一种方式是作为一个记录,其中有一组特定的已知密钥,每个密钥指向它自己的类型值(例如,{a: number, b: string}

这两种类型具有非常不同的含义,尽管通常可以将它们应用于特定的对象。类型系统使它们保持不同并迫使您将对象一种或另一种避免产生类型错误

+0

是的,这似乎是这种情况。我想我应该明确地将数据对象的类型转换为“AnySupportedObject”,因为我知道这些类型应该兼容。如果Flow提供了一种方法来检查这种显式转换的正确性,那么它会很好,但现在它似乎缺乏。 – MOZGIII

+0

这不太对。 Flow支持记录样式对象和地图样式对象之间的子类型关系。这里的问题实际上是可变的。我留下了一个解释的答案。 –

1

实际上,这与可变性有关.Flow不允许使用此代码,因为您可以d编写x.id = 5(在适当的类型改进之后),因为AnySupportedType类型允许您设置任何支持的类型,包括number作为属性。

为了解决这个问题,你需要做的对象属性协变,有效地使他们只读:

type AnySupportedObject = { +[string]: AnySupportedType };

注意添加+的。

一旦你这样做,流允许原来的任务,但阻止你设置x属性。

查看try的完整示例。

请参阅https://flow.org/blog/2016/10/04/Property-Variance/

+0

我检查了你的例子,我认为有一个问题 - 有一个数字赋值给'x.id',这个类型系统合理地不允许(流程显示错误)。然而,当我用一个字符串替换数字(这是与'DataID'类型兼容) - 我得到相同的错误。 – MOZGIII

+0

这是正确的,因为'x'具有类型'AnySupportedObject' - Flow不知道它来自具有'Data'类型的变量。要么你可以在AnySupportedObject上允许突变,要么你可以获得协变属性 - 你不能安全地拥有这两个属性。 –

+0

类型不是不透明的。我只想在那里做一个类型转换,在这之后,''Data''类型的信息必须完全丢弃。它在那里不起作用的原因是因为在'x'处仍然有对同一个对象的引用。所以它的作品,如果我使用'const x:AnySupportedType = {...y};'而不是简单的分配。 – MOZGIII