流类型不适用于匿名函数中的外部范围变量

时间:2018-02-15 12:50:41

标签: javascript reactjs ecmascript-6 redux flowtype

我为调度到reducer的操作定义了一个类型:

type RemoveQuestionAction = {
  type: 'REMOVE_QUESTION',
  questionId: number,
  docTypeId: number,
};

type QuestionAction =
  | RemoveQuestionAction
  | ...

reducer检查每个动作的类型:

const questions = (
  state : QuestionState = defaultState,
  action : QuestionAction
) : QuestionState => {...};

字段questionId在几个数组过滤器中引用:

  case REMOVE_QUESTION: {

    return {
      ...state,
      byId: state.allIds
                             // Throws error
        .filter(id => id !== action.questionId)
        .reduce((col, id) => ({
          ...col,
          [id]: state.byId[String(id)],
        }), {}),
                                               // Throws error
      allIds: state.allIds.filter(id => id !== action.questionId),
    };    
  }

这会引发action.questionId的类型错误。

但是,如果操作中的值放在变量中,则很高兴:

  case REMOVE_QUESTION: {
    let { questionId } = action; // Ok with this

    return {
      ...state,
      byId: state.allIds
        .filter(id => id !== questionId)
        .reduce((col, id) => ({
          ...col,
          [id]: state.byId[String(id)],
        }), {}),
      allIds: state.allIds.filter(id => id !== questionId),
    };    
  }

为什么我不能直接使用action的值?

这是REPL

它在REPL中按预期执行,真的很奇怪,因为我看不出有什么不同......

Flow是版本6.23

1 个答案:

答案 0 :(得分:1)

由于the doc for type refinement中解释的细化失效,

action.questionId会引发错误。在action进行细化后执行RemoveQuestionAction的箭头函数时,Flow无法确定filter()是否仍为case REMOVE_QUESTION:

我们人类知道filter() 立即执行给定的回调函数,例如id => id !== action.questionId,因此根本无法修改action。但是,从flow的角度来看,filter()只是一个将回调函数作为参数的函数,而回调函数可以像addEventListener()那样稍后执行。如果稍后可以执行回调函数,则有可能修改action并且类型细化不再成立。这就是为什么flow在这种情况下使action的类型细化无效的原因。