2017-09-01 74 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