1

I'm attempting to configure the dispatch type on a redux store that is using thunk middleware and an optional middleware logger (redux-logger).

This correctly infers the thunk type on store's dispatch...

import { createStore, applyMiddleware } from 'redux';
import thunk, { ThunkMiddleware } from 'redux-thunk';

// ...

const preloadedState = undefined;
export const store = createStore(rootReducer, preloadedState, applyMiddleware(thunk as ThunkMiddleware));

enter image description here

When I expand the middleware to include a conditional logger and spread an array of middleware into applyMiddleware, the store's dispatch is not correctly inferred.


import { createStore, applyMiddleware, Middleware } from 'redux';
import thunk, { ThunkMiddleware } from 'redux-thunk';
import { createLogger } from 'redux-logger';

// ...

const middleware: Middleware[] = [thunk as ThunkMiddleware];

if (Settings.environment === 'development') {
  const logger = createLogger({ collapsed: (_getState, _action, logEntry) => !logEntry.error });
  middleware.push(logger);
}

const preloadedState = undefined;
export const store = createStore(rootReducer, preloadedState, applyMiddleware(...middleware));

enter image description here

This is driving me crazy, any thoughts as to how to fix the typing issue when spreading the middleware array?

2 Answers 2

4

This is where redux-toolkit comes in real handy.

Their docs mention to do it this way

import { configureStore } from '@reduxjs/toolkit'
import { useDispatch } from 'react-redux'
import rootReducer from './rootReducer'

const store = configureStore({
  reducer: rootReducer,
})

export type AppDispatch = typeof store.dispatch
export const useAppDispatch = () => useDispatch<AppDispatch>() // Export a hook that can be reused to resolve types

export default store
Sign up to request clarification or add additional context in comments.

2 Comments

Adding to this: yes, this will take correctly typed middlewares into account.
Ah okay, I can definitely see the benefit of using toolkit with thunk integrated and the dispatch type correct by default. Adding on to this, I was able to add the redux-logger via return getDefaultMiddleware().concat(logger) in the middleware callback, but the dispatch type was still getting cleared. The key was adding types for redux-logger... yarn add @types/redux-logger!
1

You are doing const middleware: Middleware[] = ... which explicitly eliminates the specific types stored in the array and only retains that they are Middleware, instead do const middleware = [...] as const to retain as much information about the contents as possible. (and then use type assertions to allow the list to be modified without retaining those types since you can't possibly rely on then anyway)

3 Comments

Ah interesting, can you expand on "and then use type assertions to allow the list to be modified without retaining those types since you can't possibly rely on then anyway"?
when you do as const it labels it a readonly array so methods like push just aren't defined, so overriding this to get a logger in there would give a slightly incorrect type when the logger is added. The more correct solution would be to do const middleware: (ThunkMiddleware | LoggerMiddleware)[] so it has enough information to infer dispatch correctly as well as allowing you to push the logger but in general that is a pain.
I posted the answer then realized why you were putting in that list to begin with and realized the answer as written wouldn't work so made a hasty amendment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.