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

问题描述 投票:0回答:2

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;
javascript reactjs redux react-redux flowtype
2个回答
3
投票

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

例如,在FetchWeatherStartAction的定义中:

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

type被宣布为string。任何字符串都可以。

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

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

你期待Flow知道FetchWeatherStartActionWeatherAction枚举的唯一可能替代品,它可以将'WEATHER_FETCH_START'作为其type财产的价值。仅基于类型,任何操作都可以具有其类型的任何值。我们唯一能确定的是它是一个字符串。

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

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中,使用语法标识符访问字段在语义上与通过其字符串名称访问它没有什么不同。


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
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.