2017-01-12 3 views
2

Я был удивлен видеть, что this example не typecheck:Уточнения потока не распространяются «вверх»?

/* @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` 

Flow знает, что может уточнить state.flag к true, но он не знает, что state может быть уточнена в { flag: true }. Это ожидалось?

ответ

1

Как и многие отношения подтипов, которые отлично смотрятся на поверхности, это разрушается изменчивостью. secondStep может сохранить ссылку на state, а firstStep может впоследствии изменить state.flag на false.

Однако это работает, если вы используете disjoint unions:

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

(tryflow)

Вы можете обнаружить, что непересекающиеся союзы соответствии с вашим случаем использования лучше в любом случае, так как тогда вы можете иметь различные свойства в вашем State объект в зависимости от значения флага.

Обратите внимание, что в этом случае Flow не позволяет установить state.flag в false, поэтому уточнение может проводиться в secondStep.

+1

Неправильно разрешить передачу 'state'' secondStep', потому что 'secondStep' может удерживать ссылку на' state', тогда 'firstStep' может мутировать' state.flag' в false. Развязанные объединения фиксируют это, потому что 'flag' является фактически неизменным, когда вы находитесь в одной ветви профсоюза или другой. –

+0

Хороший улов. Я отредактирую свой ответ, чтобы включить эту информацию. –

+0

Ах, действительно интересный момент @ RyanCavanaugh. Мне было интересно, было ли что-то вроде этого. Вот досада! –

Смежные вопросы