Redux-logic provides a method called transform, which allows actions to be transformed before they reach the reducers. This is helpful for various situations. Typically I want to dispatch an action which has only my user input, and sometimes my reducer will need supporting data in order to perform the state update.
So, I can do this in a redux-logic transform process, but this seems to conflict with typesafe-actions (which I'm also using). How can I tell typescript that my actions are getting transformed before they reach the reducer?
Imagine I dispatch with a payload like { userName: string }
but my transform process adds a property so I get { userName: 'John Doe', recordId: 9 }
.
I'm new to typescript, but realized that I know how to solve this.
In the reducer we normally import the action types, it goes like this:
// actions.ts
import { action } from 'typesafe-actions';
import actionTypes from './actionTypes';
export const someAction = (data) = action(
actionTypes.SOME_ACTION_TYPE,
{ data },
);
// reducer.ts
import { ActionType } from 'typesafe-actions';
import { StateSlice } from './types';
import * as actions from './actions';
const initialState: StateSlice = { ... };
const reducer = (state = initialState, action: ActionType<typeof actions>): StateSlice => {
...
};
So to update this to accept actions which have been modified by a redux-logic middleware, we have to tell typescript that the type has been extended. It goes like this:
// actions.ts
import { action } from 'typesafe-actions';
import actionTypes from './actionTypes';
export const someAction = (data) = action(
actionTypes.SOME_ACTION_TYPE,
{ data },
);
// reducer.ts
import { ActionType } from 'typesafe-actions';
import { StateSlice, SOME_TYPE } from './types';
import * as actions from './actions';
type OriginalAction = ActionType<typeof actions.someAction>;
interface MutatedAction1 extends OriginalAction {
payload: OriginalAction['payload'] & {
thingWeAddedInReduxLogic: SOME_TYPE;
};
}
// repeat for other actions, then use a union type like this
type MutatedActionType = MutatedAction1 | MutatedAction2 | ... ;
const initialState: StateSlice = { ... };
const reducer = (state = initialState, action: MutatedActionType): StateSlice => {
...
};
This is an abbreviated version of the real code that I was able to make work. Hope this helped someone.