Набрав редуктор с библиотекой redux-actions

Я пытаюсь набрать второй аргумент, действие, моего редуктора теперь, когда я использую createAction от redux-actions библиотека.

Часть моего кода редуктора выглядит следующим образом

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,

1 ответ

Решение

Отказ от ответственности: у меня нет локально установленных библиотек redux или redux-actions, поэтому я не могу быть уверен на 100%, верен ли этот ответ; пожалуйста, проверьте это.


ShoppingCartActions дискриминационный союз, где type является дискриминантным свойством. Вы ожидаете, что TypeScript будет действовать так, как объявлено, когда вы проверяете дискриминант: он должен автоматически сузить тип action переменная для соответствующей составляющей союза.

К сожалению, вы разрушаете action на две переменные, type а также payload как это:

const { type, payload } = action;    

и компилятор не понимает, что типы type а также payload взаимосвязаны. То есть, если вы сузили type от AddItems | RemoveItem в AddItems, компилятор не сужается автоматически payload от CartItem | number в 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;
  }
}

Я думаю, теперь это должно работать как задумано.


Надеюсь, это поможет. Удачи!

Другие вопросы по тегам