Redux操作打字稿返回类型不起作用

时间:2020-01-24 12:30:42

标签: javascript reactjs typescript redux

因此,基本上,我试图返回一组函数的类型,并能够在我的redux reducer中进行匹配。

这是我的尝试:

actions.ts

export const SET_CART_ITEMS = "SET_CART_ITEMS";
export const SET_CART_TOTALS = "SET_CART_TOTALS";

export const ADD_CART_ITEM = "ADD_CART_ITEM";
export const REMOVE_CART_ITEM = "REMOVE_CART_ITEM";

export const SET_CART_LOADING = "SET_CART_LOADING";

export function setCart(cart: Cart) {
  return {
    type: SET_CART_ITEMS,
    cart
  } as const;
}

export function setTotals(totals: CartTotal) {
  return {
    type: SET_CART_TOTALS,
    totals
  }
}

export function addCartItem(cart: Cart) {
  return {
    type: ADD_CART_ITEM,
    cart
  } as const;
}

export function removeCartItem(cart: Cart) {
  return {
    type: REMOVE_CART_ITEM,
    cart
  } as const;
}

export function toggleCartLoading(loading: boolean) {
  return {
    type: SET_CART_LOADING,
    loading
  } as const;
}

export type CartActions = ReturnType<typeof setCart>| ReturnType<typeof addCartItem> | ReturnType<typeof removeCartItem> | ReturnType<typeof toggleCartLoading> | ReturnType<typeof setTotals>

reducer.ts

import { 
   CartActions,  
   ADD_CART_ITEM,
   REMOVE_CART_ITEM,
   SET_CART_ITEMS,
   SET_CART_TOTALS,
   SET_CART_LOADING 
} from '../../../actions';

export default (state: CartState = initialState, action: CartActions) : CartState => {
  switch (action.type) {
    case ADD_CART_ITEM:
      return {
        ...state,
        cart: {
          ...action.cart
        }
      }
    case REMOVE_CART_ITEM:
      return {
        ...state,
        cart: {
          ...action.cart
        }
      }
    case SET_CART_ITEMS:
      return {
        ...state,
        cart: action.cart
      }
    case SET_CART_TOTALS:
      return {
        ...state,
        totals: action.totals
      }
    case SET_CART_LOADING:
      return {
        ...state,
        loading: action.loading
      }
    default:
      break;
  }
  return state;
}

这根本不起作用,我得到的错误是在减速器开关上说的:

"Property 'cart' does not exist on type 'CartActions'.
  Property 'cart' does not exist on type '{ type: string; totals: CartTotal; }'."


Property 'loading' does not exist on type '{ readonly type: "SET_CART_ITEMS"; readonly cart: Record<string, CartItem>; } | { readonly type: "ADD_CART_ITEM"; readonly cart: Record<string, CartItem>; } | { ...; } | { ...; } | { ...; }'.
  Property 'loading' does not exist on type '{ readonly type: "SET_CART_ITEMS"; readonly cart: Record<string, CartItem>; }'.ts(2339)

我缺少明显的东西吗?我真的不希望通过接口手动键入所有操作。

来自https://gist.github.com/schettino/c8bf5062ef99993ce32514807ffae849的灵感

2 个答案:

答案 0 :(得分:1)

使用实现CartActions的方式,您应始终为其分配每个操作的类型。

例如,您应该更改:

case REMOVE_CART_ITEM:
  return {
    ...state,
    cart: {
      ...action.cart
    }
  }

对此:

case REMOVE_CART_ITEM:
  return {
    ...state,
    cart: {
      ...action.cart
    }
  } as ReturnType<typeof removeCartItem>

或者您可以修改您的CartActions,以便键入充当分隔符:

const enum ActionTypes {
  SET_CART_ITEMS,
  SET_CART_TOTALS,
  ADD_CART_ITEM,
  REMOVE_CART_ITEM,
  SET_CART_LOADING
}



type CartActions =
  | {
      type:
        | ActionTypes.SET_CART_ITEMS
        | ActionTypes.ADD_CART_ITEM
        | ActionTypes.REMOVE_CART_ITEM;
      cart: Cart;
    }
  | {
      type: ActionTypes.SET_CART_TOTALS;
      totals: CartTotal;
    }
  | {
      type: ActionTypes.SET_CART_LOADING;
      loading: boolean;
    };

export function setCart(cart: Cart): CartActions {
  return {
    type: ActionTypes.SET_CART_ITEMS,
    cart
  };
}

export function setTotals(totals: CartTotal): CartActions {
  return {
    type: ActionTypes.SET_CART_TOTALS,
    totals
  };
}

export function addCartItem(cart: Cart): CartActions {
  return {
    type: ActionTypes.ADD_CART_ITEM,
    cart
  };
}

export function removeCartItem(cart: Cart): CartActions {
  return {
    type: ActionTypes.REMOVE_CART_ITEM,
    cart
  };
}

export function toggleCartLoading(loading: boolean): CartActions {
  return {
    type: ActionTypes.SET_CART_LOADING,
    loading
  };
}

答案 1 :(得分:1)

每个动作创建者的返回类型都必须用as const注释,以便TS可以在化简器的switch语句中区分您的动作。

setTotals中,似乎缺少此const断言-添加后,至少提供的代码在playground中可以再次工作。

您可以创建一个通用动作创建者以使其更具扩展性,并省略as const

function createAction<T extends string, U, K extends string>(type: T, key: K, payload: U) {
  return ({
    type,
    [key]: payload
  }) as { type: T; } & { [P in K]: U }
  // need to cast, so TS doesn't return a widened index signature type
}

export function setTotals(totals: CartTotal) {
  return createAction(SET_CART_TOTALS, "totals", totals)
}
// same with the other functions

Code sample in Playground