I'm new to the react world, i'm trying to write an app using NextJs + reduxjs/toolkit and MUI and TypeScript. I'm having trouble with the TypeScript part of the reduxjs/toolkit. This is my **store/user-preferences-silce.ts **
import { ThemeOptions } from "@mui/material";
import { createSlice } from "@reduxjs/toolkit";
import { defaultThemeOption } from "../styles/theme/themeOptions";
export type UserPreferencesSliceState = {
theme: ThemeOptions;
};
const initialState: UserPreferencesSliceState = {
theme: defaultThemeOption,
};
const userPreferencesSlice = createSlice({
name: "userPreferences",
initialState,
reducers: {
toggleThemeMode(state) {
state.theme!.palette!.mode =
state.theme!.palette!.mode === "light" ? "dark" : "light";
},
},
});
export const userPreferencesActions = userPreferencesSlice.actions;
export default userPreferencesSlice.reducer;
Then my store/index.ts
import { configureStore } from "@reduxjs/toolkit";
import userPreferencesReducer from "./user-preferences-slice";
const store = configureStore({
reducer: {
userPreferences: userPreferencesReducer,
},
});
// 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;
export default store;
But when i'm using the state like in my Layout.tsx
import { createTheme, ThemeProvider } from "@mui/material/styles";
import { useSelector } from "react-redux";
import { RootState } from "../../store";
import { ThemeOptions } from "@mui/material";
import { useMemo } from "react";
const Layout: React.FC = (props) => {
const themeOptions: ThemeOptions = useSelector<RootState>(
(state) => state.userPreferences.theme
);
const theme = useMemo(() => {
return createTheme(themeOptions);
}, [themeOptions]);
return <ThemeProvider theme={theme}>{props.children}</ThemeProvider>;
};
export default Layout;
I got this warning
Type 'unknown' not assignable to type 'ThemeOptions'
referred to this part
const themeOptions: ThemeOptions = useSelector<RootState>(
(state) => state.userPreferences.theme
);
Can someone help my understand how to handle the type of the redux slices? Thank you
As you can see in the useSelector
type definition, the hook accepts two generic types: The first one, TState
, is the store state type, and the second one Selected
is the selectors return type. By default, both generics are optional and the return type is unknown
, that's why TypeScript complains.
There are two possible solutions to this:
you can either explicitly state the expected return type for your selector by passing ThemeOptions
as the second generic type:
const themeOptions: ThemeOptions = useSelector<RootState, ThemeOptions>(/* ... */)
or you leave the work to TypeScript by using type inference:
const themeOptions = useSelector((state: RootState) => state.userPreferences.theme)
Take note on how I removed the generic <RootState>
declaration and added its declaration to the selector parameter instead. This way, it will infer the TState
from the method signature and Selected
from its return type. Additionally, I removed the : ThemeOptions
type declaration on the const to further infer the type, which is optional.