Flow抱怨减速器中的动作联合类型

时间:2017-07-24 09:36:41

标签: javascript reactjs redux react-redux flowtype

Flow为每个参数抛出3个错误(找不到属性)(action.location,action.weatherResult和action.error)。我找到的唯一解决方案是不联合并且只有一个动作类型,其中3个不同的属性作为可选的maybes但属性不是可选的,因此它不能解决我的问题。

操作

// @flow
import actionTypes from './index';    

export type FetchWeatherStartAction = {
  type: string,
  location: string
};    

export type FetchWeatherSuccessAction = {
  type: string,
  weatherResult: ?string
};    

export type FetchWeatherFailAction = {
  type: string,
  error: string | false
};    

export type WeatherAction = FetchWeatherStartAction | FetchWeatherSuccessAction | FetchWeatherFailAction;    

const fetchWeatherStart = (location: string): FetchWeatherStartAction => ({
  type: actionTypes.WEATHER_FETCH_START,
  location
});    

const fetchWeatherSuccess = (weatherResult: ?string): FetchWeatherSuccessAction => ({
  type: actionTypes.WEATHER_FETCH_SUCCESS,
  weatherResult
});    

const fetchWeatherFail = (error: string | false): FetchWeatherFailAction => ({
  type: actionTypes.WEATHER_FETCH_FAIL,
  error
});    

export {
  fetchWeatherStart,
  fetchWeatherSuccess,
  fetchWeatherFail
}

动作类型

// @flow
const actionTypes = {
  WEATHER_FETCH_START: 'WEATHER_FETCH_START',
  WEATHER_FETCH_SUCCESS: 'WEATHER_FETCH_SUCCESS',
  WEATHER_FETCH_FAIL: 'WEATHER_FETCH_FAIL'
}    

export default actionTypes;

减速

// @flow
import actionTypes from './../actions';
import type { WeatherAction } from './../actions/weather';    

/*export type WeatherActionType = {
  type: string,
  error?: boolean | string,
  weatherResult?: string | null,
  location?: string
};*/    

export type WeatherStateType = {
  location: string,
  fetchedFromServer: boolean,
  isFetching: boolean,
  fetchError: boolean | string,
  weatherResult: ?string
};    

const defaultState: WeatherStateType = {
  location: 'Barcelona',
  fetchedFromServer: false,
  isFetching: false,
  fetchError: false,
  weatherResult: null
};    

const weather = (state: WeatherStateType = defaultState, action: WeatherAction): WeatherStateType => {    

  switch (action.type) {    

    case actionTypes.WEATHER_FETCH_START:
      return {
        ...state,
        isFetching: true,
        fetchError: false,
        location: action.location
      };    

    case actionTypes.WEATHER_FETCH_SUCCESS:
      return {
        ...state,
        fetchedFromServer: true,
        isFetching: false,
        fetchError: false,
        weatherResult: action.weatherResult
      };    

    case actionTypes.WEATHER_FETCH_FAIL:
      return {
        ...state,
        fetchedFromServer: false,
        isFetching: false,
        fetchError: action.error
      };    

    default:
      return state;
  }    

};    

export default weather;

2 个答案:

答案 0 :(得分:3)

您正在尝试依赖未在您的类型中实际编码的类型信息。

例如,在FetchWeatherStartAction

的定义中
export type FetchWeatherStartAction = {
  type: string,
  location: string
};

type被声明为string。任何字符串都可以。

但后来,在这个转换案例中:

switch (action.type) {    
    case actionTypes.WEATHER_FETCH_START:
        ...
        action.location
        ...

您希望Flow知道FetchWeatherStartAction唯一的可能替代的WeatherAction枚举,可以'WEATHER_FETCH_START'作为其type的值1}}属性。仅基于类型,任何操作可以为其类型具有任何值。我们唯一能确定的是它是一个字符串。

解决方案是将您的操作变体定义为具有更多特定类型,这些类型包含其合法值。

export type FetchWeatherStartAction = {
  type: 'WEATHER_FETCH_START',
  location: string
};    

export type FetchWeatherSuccessAction = {
  type: 'WEATHER_FETCH_SUCCESS',
  weatherResult: ?string
};    

export type FetchWeatherFailAction = {
  type: 'WEATHER_FETCH_FAIL',
  error: string | false
};  

当您检查type === 'WEATHER_FETCH_START'时,Flow可以某些表示实际类型为FetchWeatherStartAction。这是可能的,因为它已经知道actionWeatherActionWeatherAction是一个只有 这三个可能值的枚举。

你不得不重复字符串文字,而不是引用常量,这有点不幸。我知道人们对此感到不安,但我认为在这种情况下,魔术常量被认为是不良行为的所有原因都由Flow的类型检查处理。在Javascript中,使用语法标识符访问字段在语义上与通过其字符串名称访问它没有什么不同。

答案 1 :(得分:0)

万一有人偶然发现这个问题。

根本原因:Flow将在您进行函数调用时删除对类型的所有优化。

解决方案:在进行函数调用之前访问参数

例如,在您的情况下,reducer可以这样写:

const reducer = (state: {}, action: WeatherAction): WeatherStateType => {
    switch (action.type) {
      case actionTypes.WEATHER_FETCH_START:
          const {location} = action;
          return { ...state, isFetching: true, fetchError: false, location: location};
      case actionTypes.WEATHER_FETCH_SUCCESS:
          const {weatherResult} = action;
          return {...state, fetchedFromServer: true, isFetching: false, fetchError: false,, weatherResult: weatherResult};
      case actionTypes.WEATHER_FETCH_FAIL:
          const {error} = action;
          return {...state. fetchedFromServer: false, isFetching: false, fetchError: action.error};
      default: 
          return state
    }
}