I'm very new to Redux / Redux toolkit, and I'm just trying to wrap my head around how to organize my store state. Basically I'm trying to group multiple slices of my store together but having issue getting typescript to accept it.
What I'm trying to acheive:
const fooSlice = createSlice(...);
const barSlice = createSlice(...);
const eggzSlize = createSlice(...);
const store = configureStore({
reducer: {
myGroupedSlice: {
// Group these together under a property
foo: fooSlice.reducer,
bar: barSlice.reducer,
},
eggz: eggzSlize.reducer
}
});
// Typed hooks - as per the docs
type RootState = ReturnType<typeof store.getState>;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
type AppDispatch = typeof store.dispatch;
export const useAppDispatch: () => AppDispatch = useDispatch;
// So I can then use the selectors as such
const barValue = useAppSelector((state) => state.myGroupedSlice.bar);
const eggzValue = useAppSelector((state) => state.eggz);
I have tried using combineReducers
in multiple ways:
myGroupedSlice
like myGroupedSlice: combineReducers({ foo: fooSlice, bar: barSlice})
. Typescript gives an error if I also add the eggz
reducer alongside it, and in both cases the useAppSelector
loses it's typing to any
.reducer: combineReducers({ myGroupedSlice: combineReducers(...), eggz: eggzSlice.reducer})
. In this case, typescript doesn't error immediately, but the useAppSelector
hook will lose it's type to any
.In the cases where Typescript technically allows it, I haven't actually tested to see if they're working even with malfunctioning type check.
As requested, I have created a sandbox: https://codesandbox.io/p/sandbox/damp-meadow-w5wrc6
While experimenting with the issue, I realised the problem is actually only ever present when I add a middleware to it; in this case, creating the store as such:
export const listenerMiddleware = createListenerMiddleware();
const store = configureStore({
reducer: {
myGroupedSlice: combineReducers({
foo: fooSlice.reducer,
bar: barSlice.reducer,
}),
eggz: eggzSlice.reducer,
},
/*
The middleware `getDefaultMiddleware` appears to type `myGroupedslice` as
`unknown`, leading to a conflict in the `myGroupedSlice` type
*/
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(listenerMiddleware.middleware),
});
I figured out the solution to the issue: pulling the "definition" of myGroupedSlice outside of the configureStore will evaluate the types correctly:
const myGroupedSliceReducers = combineReducers({
foo: fooSlice.reducer,
bar: barSlice.reducer,
});
const store = configureStore({
reducer: {
myGroupedSlice: myGroupedSliceReducers,
eggz: eggzSlice.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(listenerMiddleware.middleware),
});
// No typescript errors and works correctly