2017-01-12 1 views
2

Ich war überrascht zu sehen, dass this example nicht funktioniert typecheck:Fließen die Verfeinerungen nicht "nach oben"?

/* @flow */ 

type State = { flag: boolean } 

function firstStep(state: State) { 
    if (state.flag) { 
    secondStep(state) 
    // this works though: 
    // secondStep({ flag: state.flag }) 
    } 
} 

function secondStep(state: { flag: true }) {} 

3: type State = { flag: boolean } 
        ^boolean. Expected boolean literal `true` 
13: function secondStep(state: { flag: true }) {} 
           ^boolean literal `true` 

Fluss weiß es state.flag zu true verfeinern, aber es weiß nicht, dass state-{ flag: true } verfeinert werden kann. Wird das erwartet?

Antwort

1

Wie viele Subtyp Beziehungen mit, die auf der Oberfläche gut aussehen, wird dies durch Veränderlichkeit ruiniert. secondStep könnte einen Verweis auf state behalten und firstStep später state.flag-false ändern könnte.

Dies schließt jedoch funktionieren, wenn Sie disjoint unions:

type State = { flag: true } | { flag: false }; 

(tryflow) verwenden

Sie können feststellen, dass disjunkte Gewerkschaften sowieso besser Ihren Anwendungsfall anpassen, da dann können Sie verschiedene Eigenschaften haben in Ihrem State Objekt abhängig vom Wert des Flags.

Beachten Sie, dass Flow in diesem Fall nicht erlaubt, state.flag auf false zu setzen, so dass die Verfeinerung in secondStep gespeichert werden kann.

+1

Es ist nicht gesund sein würde vorbei 'state' zu' secondStep' zu ermöglichen, weil 'secondStep' zu' state' zu ​​einem Referenzfesthalten konnte, dann 'firstStep' könnte mutieren' state.flag' auf false gesetzt. Disjunkt Gewerkschaften zu beheben, dass, weil 'flag' effektiv unveränderlich, wenn Sie in einem Zweig der Vereinigung oder die andere sind. –

+0

Guter Fang. Ich bearbeite meine Antwort, um diese Informationen hinzuzufügen. –

+0

Ah, wirklich interessanter Punkt @RyanCavanaugh. Ich habe mich gefragt, ob so etwas nicht der Fall war. Schade! –