Defining State Types for React-Redux useSelector in TypeScript: Best Practices and Solutions

Dec 08, 2025 · Programming · 10 views · 7.8

Keywords: React-Redux | TypeScript | useSelector

Abstract: This article explores how to effectively define state types when using the React-Redux useSelector hook in TypeScript to avoid 'unknown' type errors. By analyzing the best answer, it details methods for deriving RootState types using ReturnType from combineReducers or configureStore, and provides implementation schemes for custom typed hooks. The content covers core concepts, code examples, and common issue resolutions, helping developers enhance type safety and development efficiency.

Introduction

When managing state with React-Redux, the useSelector hook is a common way to access Redux store state. However, in TypeScript environments, default type inference may mark the state parameter as unknown, leading to type errors, such as "Object is of type 'unknown'" when trying to access state.SLICE_NAME. This article aims to resolve this issue by providing systematic methods to define state types, avoiding the tedium of manual type maintenance.

Problem Analysis

In the provided code example, the useSelector call in ChildComponent.tsx attempts to extract the navDrawer slice from the state, but since the state type is not explicitly defined, TypeScript treats it as unknown, causing errors when accessing properties. This highlights the inconvenience and error-proneness of manually defining types when dynamically adding new state slices.

Core Solution: Deriving RootState with ReturnType

According to the best answer (Answer 1, score 10.0), the most effective approach is to use TypeScript's ReturnType utility type to automatically derive the root state type from Redux's reducer or store. This avoids the need for manual type definitions and ensures that types stay in sync with code structure updates.

Deriving from combineReducers: If using combineReducers to combine multiple reducers, define the RootState type as follows:

import { combineReducers } from '@reduxjs/toolkit';
const rootReducer = combineReducers({
  // Define reducer object
});
export type RootState = ReturnType<typeof rootReducer>;

Deriving from configureStore: If creating a store directly with configureStore, derive the type via the store's getState method:

import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
  reducer: rootReducer,
});
export type RootState = ReturnType<typeof store.getState>;

In components, apply the RootState type directly to the state parameter of useSelector:

import { useSelector } from 'react-redux';
import { RootState } from './store';
const navDrawerState = useSelector((state: RootState) => state.navDrawer);

This method is concise and type-safe, requiring no additional specification of return types, as TypeScript infers them automatically.

Custom Typed Hook Scheme

Referencing other answers (e.g., Answer 2, score 4.5), a custom useSelector hook can be created to unify types across the application. This is achieved using the TypedUseSelectorHook type:

import {
  useSelector as useReduxSelector,
  TypedUseSelectorHook,
} from 'react-redux';
import { RootState } from './store';
export const useSelector: TypedUseSelectorHook<RootState> = useReduxSelector;

In components, use the custom useSelector directly without explicitly specifying state types:

import { useSelector } from './customHooks';
const navDrawerState = useSelector(state => state.navDrawer);

This enhances code maintainability and consistency, especially in large-scale projects.

Practical Example and Code Refactoring

Based on the original code, refactor store.ts to export the RootState type:

import { configureStore } from 'redux-starter-kit';
import reducer from './reducers';
const store = configureStore({
  reducer,
});
export type RootState = ReturnType<typeof store.getState>;
export default store;

In ChildComponent.tsx, apply the type definition:

import React, { FC } from 'react';
import { useSelector } from 'react-redux';
import { RootState } from './store';
const ChildComponent: FC = () => {
  const navDrawerState = useSelector((state: RootState) => state.navDrawer);
  return <div>{navDrawerState.open ? 'Open' : 'Closed'}</div>;
};
export default ChildComponent;

This eliminates type errors and keeps the code clear and type-safe.

Summary and Best Practice Recommendations

This article presents core methods for defining state types in React-Redux useSelector within TypeScript. It is recommended to use ReturnType<typeof store.getState> or ReturnType<typeof rootReducer> to automatically derive RootState, combined with direct type annotations or custom hooks for application. This ensures type accuracy and scalability, avoiding the burden of manual maintenance. In practice, choose the appropriate method based on project structure and ensure @types/react-redux is installed for type support. By following these practices, developers can improve code quality and development efficiency.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.