1

The the official Redux Toolkit docs recommend typing the RootState as follows:

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

export const store = configureStore({
  reducer: {
    posts: postsReducer,
    comments: commentsReducer,
    users: usersReducer,
  },
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

However, when using Redux with server-side rendering (SSR) framework like Gatsby, I need to export my configureStore call as a callable function, so I can be sure it is only instantiated once:

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

// 'store' is recommended by the gatsby team to be a function,
// See https://github.com/gatsbyjs/gatsby/blob/master/examples/using-redux/wrap-with-provider.js
export const store = () => configureStore({
  reducer: {
    posts: postsReducer,
    comments: commentsReducer,
    users: usersReducer,
  },
})

// TODO: won't work because store is not a const anymore, it is a function!
// Infer the `RootState` and `AppDispatch` types from the store itself
// export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
// export type AppDispatch = typeof store.dispatch

anybody know how I can reconcile keeping the configure store call a function (to follow Gatsby best practices), yet still getting the RootState type out somehow (so I can use things like useSelector throughout my app)?

fullStackChris
  • 1,300
  • 1
  • 12
  • 24

1 Answers1

5

Hold on to your hats for this one:

type ConfiguredStore = ReturnType<typeof store>;
type StoreGetState = ConfiguredStore["getState"];
export type RootState = ReturnType<StoreGetState>;
export type AppDispatch = ConfiguredStore["dispatch"];

As a side note, I'd suggest naming that function makeStore or something like that, rather than just calling it store.

fullStackChris
  • 1,300
  • 1
  • 12
  • 24
markerikson
  • 63,178
  • 10
  • 141
  • 157
  • Excellent! It works! I've modified your code to export the two exports needed in the app, `RootState` and `AppDispatch`. I forgot that for completeness we should include the `AppDispatch` type as well, following the Redux Toolkit recommendations. – fullStackChris May 16 '21 at 12:16