Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Property 'y' does not exist on type 'DefaultRootState'

I have a src/reducers/index.tsx file where I output all my reducers:

import counterReducer from '../reducers/counter';
import loggedReducer from '../reducers/isLogged';
import {combineReducers} from 'redux';

const allReducers = combineReducers({
   counter: counterReducer,
   isLogged: loggedReducer,
});

export default allReducers;

Then in my src/index.tsx:

import {Provider} from 'react-redux';

const store = createStore(allReducers);

ReactDOM.render(
   <React.Fragment>
      <Provider store={store}>
        <App />
      </Provider>,
   document.getElementById('root'),
);

And finally in my src/app.tsx I have:

import {useSelector} from 'react-redux';

const App = () => {
   const counter = useSelector(state => state.counter);
   return (
      <h1>counter {counter}</h1>
   );
};

The error is reported in the state.counter part of the useSelector:

> Property 'counter' does not exist on type 'DefaultRootState'.ts(2339)

It looks like the store is never actually created?

like image 743
Peter Boomsma Avatar asked Aug 04 '20 09:08

Peter Boomsma


People also ask

How to solve'property does not exist on type {}'error?

The "Property does not exist on type ' {}'" error occurs when we try to access or set a property that is not contained in the object's type. To solve the error, type the object properties explicitly or use a type with variable key names. Copied!

Why can't I assign properties to an empty object?

We didn't explicitly type the obj variable and declared it to an empty object, so we aren't able to assign or access properties that don't exist on the object's type.

Is there a defaultrootstate type for the default state?

There's no DefaultRootState.ts the error refers to the DefaultRootState type, the . ts (2339) is just formatting. By defining a custom type for the state I resolved the error. Check answer :). Non-hacky answer inbound!

How to fix “property ‘user’ does not exist on type ‘request’” error with express?

To fix the "Typescript Error: Property ‘user’ does not exist on type ‘Request’" error with Express, we can add our own definition for the request type. into a TypeScript type definition file. We create the IGetUserAuthInfoRequest interface the extends the Request interface by adding the user field.


3 Answers

Non-hacky answer inbound!

Shortest Answer:

Link to Redux Toolkit docs for creating typed react-redux hooks: https://react-redux.js.org/using-react-redux/usage-with-typescript#define-root-state-and-dispatch-types

(While this is a link to the Redux Toolkit docs, I believe this technique should still work with "vanilla" react-redux. Please someone correct me with a comment if I'm wrong.)

Short Answer:

The useSelector hook by itself is unaware of the typing that should be applied to the state you want to use. You'll have to do a couple lines of work to earn your type safety! Utilizing the technique shown in the link, you'll get to have the typings for your state every time you use it. You'll create a one-line custom hook that utilizes the native useSelector hook with the inferred types from your root state to find out what your states' types are supposed to be.

Longer Answer:

The useSelector hook by itself is unaware of the typing that should be applied to the state you want to use. To make it so that the types of your store get captured and applied to your useSelector hooks, you'll need to jump through two small hoops. We're also going to take care of your useDispatch hook while we're at it.

Step 1

Let's grab the inferred types from the store. To do this, we'll go to where our store is created and use some Typescript magic to get the inferred types from the state:

// Copied from Redux Toolkit docs that are linked above
// store.ts

import rootReducer from './rootReducer'

const store = createStore(rootReducer)

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

Brief pause to unpack lines 6 and 7:

Line 6: export type RootState = ReturnType<typeof store.getState>

  • ReturnType means "The return type of the function."

  • typeof means "Tell me what the types are of this thing."

  • store.getState is a function that returns the state object that is currently in the store.

Now put those pieces together!: Whatever is being returned from store.getState, I want the types stored as the RootState variable!


Line 7: export type AppDispatch = typeof store.dispatch

  • typeof means "Tell me what the types are of this thing."
  • store.dispatch means "I want the dispatch object used to dispatch actions to the store."

Now put those pieces together!: Get the dispatch object from the store, break it down into it's types, and store it in the AppDispatch variable!

Step 2

Now that we have the inferred types from our store and dispatch, we can apply them to our hooks. We will do this by creating a custom hook so that we don't have to handle typing our hooks every time we go to use them:

// Copied from Redux Toolkit docs that are linked above
// hooks.ts

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

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

Here, we are taking the types that we created in store.ts and applying them to the useDispatch and useSelector hooks that we normally use in react-redux. From now on, you'll have your types set up for you when you use your new custom hooks!


Voila! You now have type safety in your react-redux hook implementation!

like image 84
Anthony Shew Avatar answered Oct 19 '22 15:10

Anthony Shew


This works for me.

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

const { domain } = useSelector(
 (state: RootStateOrAny) => state.currentSite?.site,
);
like image 7
aqib Avatar answered Oct 19 '22 15:10

aqib


It was indeed a TypeScript issue. There were a few things I changed to get my app to compile and also to work with Redux. I know we shouldn't post links but https://github.com/piotrwitek/react-redux-typescript-guide this is a great resource! Based on the examples there I fixed my issues:

I changed the useSelector to define a type to the state, this resolved the original error.

import {RootState} from 'typesafe-actions';
const counter = useSelector((state: RootState) => state.counter);

But what is RootState? RootState is a custom type created in the src/store/types.d.ts file:

import {StateType, ActionType} from 'typesafe-actions';

declare module 'typesafe-actions' {
  export type Store = StateType<typeof import('./index').default>;

  export type RootState = StateType<typeof import('./root-reducer').default>;

  export type RootAction = ActionType<typeof import('./root-action').default>;

  interface Types {
    RootAction: RootAction;
  }
}
like image 3
Peter Boomsma Avatar answered Oct 19 '22 17:10

Peter Boomsma