0

I have a thunked store created like

export const store = createStore<IState, IAction<string, any>, {}, {}>(combinedReducers, applyMiddleware(thunk));

I want to dispatch a thunked action outside of a React component, like store.dispatch(myThunkedActionCreator(data));

However, the type of dispatch is coming in as Dispatch<IAction<string, any>> instead of ThunkDispatch<State, void, ActionType>, which would be the type necessary to pass a thunk to the store's modified dispatch. I import the store as import { store } from '../Store/Store';

How can I get store.dispatch to have the right, thunked dispatch type?

I know I can typecast dispatch at its callsites, but that's a hack. I'm not currently using RTK, which solves the typing problem, but that's out of scope for me at the moment.

Michael Tontchev
  • 909
  • 8
  • 23

1 Answers1

1

There's a couple problems here.

The first is that we have officially deprecated the original createStore API from the core redux package, and we do not want people using that directly in their applications! Instead, you should be using the configureStore API from our official Redux Toolkit package, which wraps createStore and sets it up with a good default configuration:

The second issue is that by explicitly adding generics to createStore, you're overriding any possible type inference that TS might do from the provided middleware like thunk. So, as far as TS is concerned, store.dispatch is still only the "basic" type that can only accept action objects - the thunk middleware modifications (which tell TS it can also accept a thunk function) are being ignored and overridden by those generics.

The best answer here is to use configureStore, which automatically adds the thunk middleware anyway, and has better TS inference for any customizations:

import { configureStore } from "@reduxjs/toolkit" 

const store = configureStore({
  reducer: combinedReducers
})

// already added the thunk middleware!
store.dispatch(myThunk())

// TS types reflect that:
// ThunkDispatch & Dispatch<AnyAction>
type AppDispatch = typeof store.dispatch
markerikson
  • 63,178
  • 10
  • 141
  • 157
  • Yeah, guess I'll have to do that eventually. One thing I don't like about allowing TS to do type inference of my state is that it can introduce weird bugs in what my state's shape actually turns out to be, whereas if I have an explicit IState, I know exactly what the state will be. – Michael Tontchev Sep 04 '22 at 00:49
  • 1
    Our recommendations are to explicitly type each _individual_ slice's state, like `TodosState` or `PostsState`... but then _infer_ the _root_ state. That way as you do add more slices, you don't have to keep updating that type directly (ie, only do the store setup process once). See https://redux.js.org/tutorials/typescript-quick-start . Plus, for _both_ `createStore` and `configureStore`, adding the actual state type as a generic argument will end up breaking the type inference overall. – markerikson Sep 04 '22 at 04:04