What is the best way to cast the action
parameter in a redux reducer with typescript? There will be multiple action interfaces that can occur that all extend a
Here's a clever solution from Github user aikoven from https://github.com/reactjs/redux/issues/992#issuecomment-191152574:
type Action = {
type: string;
payload: TPayload;
}
interface IActionCreator {
type: string;
(payload: P): Action
;
}
function actionCreator
(type: string): IActionCreator
{
return Object.assign(
(payload: P) => ({type, payload}),
{type}
);
}
function isType
(action: Action,
actionCreator: IActionCreator): action is Action
{
return action.type === actionCreator.type;
}
Use actionCreator
to define your actions and action creators:
export const helloWorldAction = actionCreator<{foo: string}>('HELLO_WORLD');
export const otherAction = actionCreator<{a: number, b: string}>('OTHER_ACTION');
Use the user defined type guard isType
in the reducer:
function helloReducer(state: string[] = ['hello'], action: Action): string[] {
if (isType(action, helloWorldAction)) { // type guard
return [...state, action.payload.foo], // action.payload is now {foo: string}
}
else if(isType(action, otherAction)) {
...
And to dispatch an action:
dispatch(helloWorldAction({foo: 'world'})
dispatch(otherAction({a: 42, b: 'moon'}))
I recommend reading through the whole comment thread to find other options as there are several equally good solutions presented there.