0

现在我正在努力输入我createActionredux-actions库中使用的减速器的第二个参数 action。

我的部分reducer代码如下

type AddItems = 'addItems';
const AddItems: AddItems = 'addItems';

interface AddItemAction extends Action<CartItem> {
    type: AddItems;
}

export const addItems = createAction<CartItem>(AddItems);

type RemoveItem = 'removeItem';
const RemoveItem: RemoveItem = 'removeItem';

interface RemoveItemAction extends Action<number> {
    type: RemoveItem;
}

export const removeItem = createAction<number>(RemoveItem);

export type ShoppingCartActions = AddItemAction | RemoveItemAction;

export const shoppingCartActions = {
    addItems,
    removeItem
};

export default function shoppingCartReducer(state: ShoppingCartStore = shoppingCartInitialState, action: ShoppingCartActions) {
    const { type, payload } = action;    
    switch (type) {
        case AddItems:
           return {
            cartItems: [
                ...state.cartItems.filter(cartItem => cartItem.item.id !== payload!.item.id),
                payload
            ]               
           };
        case RemoveItem:
           return {
               cartItems: [
                   ...state.cartItems.filter(cartItem => cartItem.item.id !== payload)
               ]
           };
        default:
            return state;
    }
}

我遇到的问题是,当我payload在减速器中访问属性时,它认为每个案例都必须存在该属性。例如,在addItems我访问payload.item但打字稿抱怨的情况下,因为它还寻找item来自RemoveItemAction.

4

1 回答 1

2

免责声明:我没有在本地安装 redux 或 redux-actions 库,所以我不能 100% 确定这个答案是否正确;请测试一下。


ShoppingCartActions是一个可区分的联合,其中type是判别属性。当您检查判别式时,您期望 TypeScript 像宣传的那样:它应该自动将action变量的类型缩小到联合的适当成分。

不幸的是,您正在解构action为两个变量,type如下payload所示:

const { type, payload } = action;    

并且编译器不理解 和 的类型typepayload相关的。 也就是说,如果您缩小typefrom AddItems | RemoveItemto AddItems,编译器不会自动缩小payloadfrom CartItem | numberto CartItem。尽管我们知道一定是这样,但编译器并不像我们那么聪明,它用来分析控制流 的启发式算法也不能胜任像这样理解“纠缠变量”的任务。

不是一个遇到这个问题人。_ 语言设计者在这些问题中的评论通常类似于“如果编译器可以为您执行此操作会很好,但实现起来会非常昂贵并导致编译器性能不佳”。


在这种情况下,最简单的解决方法是按照 TypeScript 的意图使用可区分联合:不要解构action。改为使用直接属性访问action

export default function shoppingCartReducer(
  state: ShoppingCartStore = shoppingCartInitialState, 
  action: ShoppingCartActions
) {
  // switch on property of action
  switch (action.type) {
    case AddItems:
      return {
        // action.payload is now CartItem
        cartItems: [              
          ...state.cartItems.filter(
            cartItem => cartItem.item.id !== action.payload!.item.id
          ),
          action.payload
        ]
      };
    case RemoveItem:
      // action.payload is now number
      return {
        cartItems: [
          ...state.cartItems.filter(
            cartItem => cartItem.item.id !== action.payload
          )
        ]
      };
    default:
      return state;
  }
}

我认为这现在应该按预期工作。


希望有帮助。祝你好运!

于 2018-05-29T13:34:05.507 回答