Набрав редуктор с библиотекой 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;
}
}
Я думаю, теперь это должно работать как задумано.
Надеюсь, это поможет. Удачи!