Search code examples
typescriptredux-toolkit

What type to use for a reducer action with an error member?


From the PayloadAction type definition, an error member can be added to the action parameter.

I then defined the type like in this example :

const reducer = createSlice({
  name: 'login',
  initialState,
  reducers: {
    cancelLogin: (state, action: PayloadAction<void, string, never, Error>) => {
      state.loggingIn = false;
      console.info(action.error.message);
    }
  }
});

Resulting in the error

Type '(state: WritableDraft<LoginState>, action: PayloadAction<void, string, never, Error>) => void'
is not assignable to type
'CaseReducer<LoginState, { payload: any; type: string; }> | CaseReducerWithPrepare<LoginState, PayloadAction<any, string, any, any>>'.
  Type '(state: WritableDraft<LoginState>, action: PayloadAction<void, string, never, Error>) => void' is not assignable to type 'CaseReducer<LoginState, { payload: any; type: string; }>'.
    Types of parameters 'action' and 'action' are incompatible.
      Type '{ payload: any; type: string; }' is not assignable to type 'PayloadAction<void, string, never, Error>'.
        Property 'error' is missing in type '{ payload: any; type: string; }' but required in type '{ error: Error; }'.ts(2322)

How could it be solved ?


Solution

  • You need to match CaseReducerWithPrepare, rather than CaseReducer, as that is the only one that allows Error in the PayloadAction. That requires you pass both the reducer, and a prepare function, instead of the reducer directly.

    const reducer = createSlice({
      name: 'login',
      initialState,
      reducers: {
        cancelLogin: { 
          reducer: (state, action: PayloadAction<void, string, never, Error>) => {
            state.loggingIn = false;
            console.info(action.error.message);
          },
          prepare: (...args) => { payload: /*initial payload*/, error: /*initial error*/ }
        }
      }
    });