'Persist-reducer function giving type error to my reducer in typescript

I am trying to configure react-persist in my typescript react application. The persistReducer function is giving a type error to my reducer that Argument of type '(state: IState | undefined, action: Action) => IState' is not assignable to parameter of type 'Reducer<unknown, Action>'. Here is my store.ts code.


const persistConfig = {
  key: "root",
  storage,
  stateReconciler: autoMergeLevel2,
  whiteList: ["reducer"],
};

const persistedReducer = persistReducer(persistConfig, reducer);//the type error

This the code I am using for my reducers

export const reducer= (state:IState=initialState, action:Action):IState=> {
    const {type, payload}=action;


    switch(type){
        case ActionType.CONNECT_META_MASK:
        return {
        ...state,
        address:payload.address,
        connection:payload.connection
        } 
        case ActionType.HOUR_PASSED:
        return {
        ...state,
        hourPassed:payload
        } 
         default:
      return state;
    }
    
}


IState


export interface IState{
    address:string,
    connection:boolean
    hourPassed:number
}

export const initialState:IState={
     address: '',
  connection: false,
  hourPassed:0
}

Action

import {ActionType} from "../types/types"


    
interface IMetaMaskConnection{
    type:typeof ActionType.CONNECT_META_MASK,
     payload:{
       connection:boolean,
       address:string
     }
}
interface IHourPassed{
  type:typeof ActionType.HOUR_PASSED,
  payload:number
}

export type Action = IMetaMaskConnection | IHourPassed



export const connectMetaMaskAction = (data:IMetaMaskConnection['payload']):Action => ({
  type: ActionType.CONNECT_META_MASK,
 payload:data
});
export const setHourPassed = (data:IHourPassed['payload']):Action => ({
  type: ActionType.HOUR_PASSED,
 payload:data
});


Instead of Action if I use AnyAction (exported from redux) then it works fine but I lose type declarations for my action payload. I have looked online but I wasn't able to find any solution.



Solution 1:[1]

I had a similar issue while trying to add the persister to my root level reducer. And it took me some time to find a solution so help this directs people to the solution: https://github.com/rt2zz/redux-persist/issues/1140 for this issue. For me to keep type declarations I had to move the persister off of the root level and onto the specific reducer. Here is my implementation of the working persister with working type declarations:

import { configureStore, ThunkAction } from "@reduxjs/toolkit";
import { AnyAction, combineReducers } from "redux";
import thunk from "redux-thunk";

import storage from "redux-persist/lib/storage";
import autoMergeLevel2 from "redux-persist/lib/stateReconciler/autoMergeLevel2";
import persistReducer from "redux-persist/es/persistReducer";
import persistStore from "redux-persist/es/persistStore";

import uiReducer, { UiState } from "./reducers/uiReducer";
import apiReducer from "./reducers/apiReducer";

const persistConfig = {
  key: "ui",
  storage,
  stateReconciler: autoMergeLevel2,
};

//Couldn't get state typings if persisting root reducer. Persisted by reducer works.
const reducers = combineReducers({
  ui: persistReducer<UiState, any>(persistConfig, uiReducer),
  api: apiReducer,
});

export const store = configureStore({
  reducer: reducers,
  middleware: [thunk],
});

export const persister = persistStore(store);

// Infer the `RootState` from the store itself to set up useAppDispatch and useAppSelector hook: https://react-redux.js.org/using-react-redux/usage-with-typescript
export type RootState = ReturnType<typeof store.getState>;

export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  AnyAction
>;

UiState is the interface for the initial uiReducer state. This is what kept the type declarations for my setup. I left in some extra stuff to help see the full setup.

Solution 2:[2]

In your root reducer, export its type:

import { combineReducers } from "@reduxjs/toolkit";

export const rootReducer = combineReducers({ ... });
export type RootReducer = ReturnType<typeof rootReducer>;

Then import it into your store and set persistReducer as below:

import { rootReducer, RootReducer } from "./reducers";

const persistedReducer = persistReducer<RootReducer>(
  persistConfig,
  rootReducer
);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Colin Hale
Solution 2 Zishan Neno