Search code examples
typescriptreduxredux-middleware

Custom middleware causes a circular reference in redux


I am trying to convert a redux project to typescript using the provided documentation:

https://redux.js.org/usage/usage-with-typescript#type-checking-middleware

However I'm having trouble doing it with my custom middleware. Here is the minimized and extracted code that causes an error for me.

store.ts:

import { configureStore } from '@reduxjs/toolkit';

import reducer from './customReducer';

import { customMiddleware } from "./customMiddleware";

const store = configureStore({
    reducer: {
        custom: customReducer
    },
    middleware: getDefaultMiddleware => getDefaultMiddleware().prepend(customMiddleware)

})

export type RootState = ReturnType<typeof store.getState>

export default store

customMiddleware.ts:

import { Middleware } from 'redux';
import { RootState } from './store';

export const customMiddleware = (): Middleware<{}, RootState> => {
    return store => next => action => {
        return next(action);
    }
}

This causes several error messages: on const store = configur...:

'store' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.

on RootState export:

Type alias 'RootState' circularly references itself.

on customMiddleware export:

'customMiddleware' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.


Solution

  • In that case, you'll have to somehow break the circle.

    Easiest way here is

    export type RootState = ReturnType<typeof customReducer>
    

    Edit: I think your initial code here was reducer: customReducer

    With the given code it won't work - you need to split out that reducer creation before the store creation:

    const rootReducer = combineRecucers({
            custom: customReducer
    })
    
    export type RootState = ReturnType<typeof rootReducer>
    
    const store = configureStore({
        reducer: rootReducer,
        middleware: getDefaultMiddleware => getDefaultMiddleware().prepend(customMiddleware)
    
    })