Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

566
Vistas
TS2339: Property 'tsReducer' does not exist on type 'DefaultRootState'

Struggling with the above question. Seen similar questions but cannot figure it out.

The below code is me attempting to open and close a dialog using TypeScript for first time in an existing React project which uses .js and .jsx.

import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import {useDispatch, useSelector} from 'react-redux';
import {closeTsDialog} from '../actions/tsDialog'
import {ActionTypes} from '../actions/types';

const TsApp = (): JSX.Element => {
    const dispatch = useDispatch();

// ERROR SHOWS UP ON LINE BELOW "state?.tsReducer?.isDialogOpen"
    const isDialogOpen = useSelector(state => state?.tsReducer?.isDialogOpen);
    const state = useSelector(s => s);
    console.log('->>>>>> state', state);


    // main tsx excluded to allow for posting on stackoverflow
};


export default TsApp;
import {TsDialogAction} from "../actions/tsDialog";


const initialState = {
    id: 0,
    isDialogOpen: false
};

const tsReducer = (state: TsDialogAction = initialState, action: Action) => {
    switch (action.type) {
        case ActionTypes.closeDialog: {
            return {...state, isDialogOpen: false};
        }
        case ActionTypes.openDialog: {
            return {...state, isDialogOpen: true};
        }
        default:
            return state;
    }
};

export default tsReducer;

import {ActionTypes} from './types';

export interface TsDialogAction { isDialogOpen: boolean number: number }

export interface CloseTsDialog { type: ActionTypes.closeDialog payload: TsDialogAction }

export interface OpenTsDialog { type: ActionTypes.openDialog payload: TsDialogAction }

export interface Increment { type: ActionTypes.increment payload: TsDialogAction }

export interface Decrement { type: ActionTypes.decrement payload: TsDialogAction }

export const closeTsDialog = (id: number) => ({type: ActionTypes.closeDialog, payload: id}); export const openTsDialog = (id: number) => ({type: ActionTypes.openDialog, payload: id}); export const incrementAction = (id: number) => ({type: ActionTypes.increment, payload: id}); export const decrementAction = (id: number) => ({type: ActionTypes.decrement, payload: id});

over 4 years ago · Santiago Trujillo
7 Respuestas
Responde la pregunta

0

You need to declare the type of the state argument in your selector, like:

const isDialogOpen = useSelector( (state: RootState) => state.tsReducer.isDialogOpen);

Please see the Redux docs on TypeScript usage, as well as the React-Redux docs page on static typing for examples.

(Also, as a stylistic note: please don't call that tsReducer in your root state. Give it a name that matches the data it's handling, like state.ui.)

over 4 years ago · Santiago Trujillo Denunciar

0

It is complaining about the type. Quick solution would be adding any as state type.

Proper solution will require following two steps:

  1. Create RootState type in Root Reducer.
export const rootReducer = combineReducers({
  dashboard: dashboardReducer,
  user: userReducer
});

export type RootState = ReturnType<typeof rootReducer>
  1. Provide RootState type to state object.
  let userData = useSelector((state: RootState) => {
    return state.user.data;
  });
over 4 years ago · Santiago Trujillo Denunciar

0

For me, a better solution than specifying state in useSelector would be as below.
As in the node_modules/@types/react-redux/index.d.ts, you can use module augmentation.

/**
 * This interface can be augmented by users to add default types for the root state when
 * using `react-redux`.
 * Use module augmentation to append your own type definition in a your_custom_type.d.ts file.
 * https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
 */
// tslint:disable-next-line:no-empty-interface
export interface DefaultRootState {}

Do as below

  1. Export AppState in reducer src/reducer/index.ts
const reducers = combineReducers({
  userReducer,
});

export type AppState = ReturnType<typeof reducers>;
  1. Create new your_custom_type.d.ts. (I prefer react-redux.d.ts).
    In src/@types/your_custom_type.d.ts
import 'react-redux';

import { AppState } from '../reducers';

declare module 'react-redux' {
  interface DefaultRootState extends AppState { };
}
  1. Add typeRoots in tsconfig.json
{
  "compilerOptions": {
    ...
    "typeRoots": ["src/@types"]
  }
}

You can use as below without specifying AppState

import React, { memo } from 'react';
import { useSelector } from 'react-redux';

export default memo(() => {
  const isLoggedIn = useSelector(
    ({ userReducer }) => userReducer.isLoggedIn
  );
  return <div>{isLoggedIn}</div>;
});
over 4 years ago · Santiago Trujillo Denunciar

0

If you are using react-redux, another out of the box solution would be to use RootStateOrAny.

import { RootStateOrAny, useSelector } from 'react-redux';

// and then use it like so in your component
...
const authState = useSelector((state: RootStateOrAny) => state.auth);
...


over 4 years ago · Santiago Trujillo Denunciar

0

These are useful articles.

  1. https://redux.js.org/recipes/usage-with-typescript#define-root-state-and-dispatch-types
  2. https://redux.js.org/recipes/usage-with-typescript#define-typed-hooks

So first define RootState and AppDispatch like following:

//at store/index.ts
const rootReducer = combineReducers({
  tsReducer: tsReducer
});
const store = createStore(rootReducer)

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

And then define hooks (useAppDispatch, useAppSelector) can be used in components.

//at store/hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './'

export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

And use it on component like following:

import {useAppSelector} from '../store/hooks'
//...
const TsApp = (): JSX.Element => {
    const dispatch = useDispatch();

// ERROR should be fixed
    const isDialogOpen = useAppSelector(state => state.tsReducer.isDialogOpen);
};
over 4 years ago · Santiago Trujillo Denunciar

0

this worked for me

import { RootStateOrAny, useSelector } from "react-redux"

const search = useSelector((state: RootStateOrAny) => state.searchObj.value)
over 4 years ago · Santiago Trujillo Denunciar

0

it is just about types that you need to satisfy to this hook, useSelector accepts DefaultRootState type, you can override its default types through this

type User = {
  firstname: string;
  lastname: string;
};
type SelectorTypes = {
  users: User[];
  //...other reducers
};
const router = useSelector<SelectorTypes>((state) => state.users);
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda