I am trying to learn redux and I am trying to implement the redux-thunk middleware. I've been following a few different tutorials and they suggest something similar to this:
import thunk from "redux-thunk";
import promise from "redux-promise-middleware";
...
const middleware = applyMiddleware(promise(), thunk);
const store = createStore(reducers, middleware);
This gives me the following error:
/Users/me/Documents/workspace/redux/node_modules/redux-thunk/index.d.ts
(4,47): Generic type 'Dispatch' requires 2 type argument(s).
Can someone please explain what is going on and how to fix this?
Many thanks
This problem turns out to be related to the new version of redux (4.0.0) being incompatible with the current version of redux-thunk (2.2.0).
See this link: https://github.com/gaearon/redux-thunk/issues/169
and this PR: https://github.com/gaearon/redux-thunk/pull/180
I think you need to type dispatch in a way:
interface IStoreState {
readonly pendingActions: number;
readonly isAuthenticated: boolean;
};
function signIn(): (dispatch: Dispatch<IStoreState>) => ....
Related article.
Related
I'm in the process of converting one of my React Firebase project to typescript with help of react-redux-firebase documentation. One of the problem I'm having is how to correctly define types for the fireabase and firestore functions. For example, here's my React reducer action function.
import { Dispatch } from "redux";
import { PROJECT_TYPES } from "../../action-types/project";
import { PROJECT_ACTION } from "../../action/project";
import { IPROJECT } from "../../interface/project";
export const createProject = (project: IPROJECT) => async (dispatch:Dispatch<PROJECT_ACTION>, getState:any, { getFirebase, getFirestore }:any):Promise<void> => {
const firestore = getFirestore();
firestore.collection('projects').add({
...project,
authorFirstName: getState().firebase.profile.firstName,
authorLastName:getState().firebase.profile.lastName,
authorId:getState().firebase.auth.uid,
createdAt:new Date()
}).then(() => {
dispatch({
type: PROJECT_TYPES.CREATE_PROJECT,
payload: project
})
}).catch((err:any) => {
console.log({err})
dispatch({ type: PROJECT_TYPES.CREATE_PROJECT_ERROR, payload: err })
})
}
As see above code I've defined the type as any to the getState, getFirebase and getFirestore functions. I'm not happy with that type, so I want to know is there a correct way to define these types?
Instructions followed from the http://react-redux-firebase.com/docs/api/getFirebase.html link
Thanks in advance.
The information for the type definitions for React Redux may be found in the #types/react-redux typedefs package on NPM. The types export certain helpers in addition to typing the library methods, making it easy to construct typesafe interfaces between your Redux store and your React components.
Because the react-redux package depends on #types/react-redux, the type definitions will be installed together with the library. Otherwise, you'll have to explicitly install them (using npm install #types/react-redux, for example).
Reading the documentation in the comments, the information could be useful, but I found more documentation that might also help with your project:
Using React + Redux with Firebase & TypeScript.
The simplest way to combine React, Redux and Firestore
(Typescript).
I've been reading the documentation on using Redux with Typescript and I think I've got everything right, but my compiler is complaining regardless.
This is the problematic line:
// Widget.tsx
const error = useTypedSelector(state => state.error.widgetError)
// ^
// Object is of type 'unknown'. TS2571
useTypedSelector is a recommended by the docs custom hook, so you won't have to typecast state as RootState whenever you use a selector.
// store.ts
export type RootState = ReturnType<typeof store.getState>
// hooks.ts
import { TypedUseSelectorHook, useSelector } from 'react-redux'
import { RootState } from './store'
export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector
I don't understand what the problem is. My entire state tree is typed, and so is the state argument in the callback. Hovering over the object in VS Code confirms this.
I've tried all sorts of typecasting to get around it, I still get the same error.
const error = useSelector((state: RootState) => state.error.widgetError) // no
const error = useSelector<RootState, string | null>(state => state.error.widgetError) // nup
const error = useTypedSelector(state => (state as RootState).error.widgetError) // nuh-uh
The only thing that worked was adding #ts-ignore, but that kind of defeats half the purpose of using typescript to begin with.
I'm out of both smart and stupid ideas at this point. Halp please?
I can't reproduce this issue on codesandbox, nor in a new react app with the typescript template. It is most likely caused by (incorrectly?) adding ts to an existing js react app.
If RootState is defined then const error = useSelector<RootState, ErrorState>((state) => state.error).widgetError; will do the job
I am using the article of Dan Abramov to sync my redux store with browser LocalStorage.
The problem is I am using typescript and when I try to create the store the following way:
const store = createStore(
App,
persistedState
);
(where persistedState is an object type of IStoreState | undefined) then typescript throws an error:
Type 'IStoreState' is not assignable to type 'StoreEnhancer<unknown, unknown>'.
My question is how can I transform my state to StoreEnhancer to succesfully pass it to createStore function?
Your error actually means that createStore is matching the wrong overload. The second argument to createStore can be either an enhancer or a preloadedState.
export interface StoreCreator {
<S, A extends Action, Ext, StateExt>(
reducer: Reducer<S, A>,
enhancer?: StoreEnhancer<Ext, StateExt>
): Store<S & StateExt, A> & Ext
<S, A extends Action, Ext, StateExt>(
reducer: Reducer<S, A>,
preloadedState?: PreloadedState<S>,
enhancer?: StoreEnhancer<Ext>
): Store<S & StateExt, A> & Ext
}
In this case it is a preloadedState and should be assignable to PreloadedState<IStoreState> which is basically a deep partial of IStoreState. Perhaps you can fix the error by tweaking the return types on your loadState() function, but I have a better solution.
You can avoid the confusion about which overload to match by using the configureStore utility from Redux Toolkit. You set your persistedState as the preloadedState property of the store config. This property is optional so undefined is okay.
const store = configureStore({
reducer: App, // can be a reducer or a reducer map object
preloadedState: persistedState,
});
You might want to look into the redux-persist package which implements this idea with lots of configuration options.
I am developing my project using React and Redux. I am getting below error when I run my project after few days later. Could anyone say why I am getting below error.
This is how I configure redux store:
const enhander = compose(applyMiddleware(...featureMiddleware, ...coreMiddleware, logger, thunk));
export const store = createStore(rootReducer, {}, enhander);
The only difference is I provide an initial state which is an empty object
Greetings.
I have a configured project with React, Redux, Immutable.js + TypeScript. During implementation I was trying to declare types as much as possible and found interesting issue. See code example below:
Short configuration of redux store
import { createStore } from 'redux';
import { combineReducers } from 'redux-immutable';
const rootReducer = combineReducers({...});
const store = createStore(rootReducer);
Somewhere inside component
// ...
const mapStateToProps = (state: ReturnType<typeof rootReducer>) => {
// state is plain object :(
};
On state hover in VS Code, tooltip shows that state is a plain object, however it is not. It should be a custom collection from Immutable.js
How can I get a correct type of rootReducer? Or what I am doing wrong?
Screenshots:
P.S. StateType and ReturnType do the same stuff
I spent a lot of time on finding a solution of how to make TypeScript work with Immutable.js in pair and unfortunately there is no explicit/trivial solution (or I didn't find it).
If you on the start of your project and looking for some alternatives I would highly recommend you to take a look at the Immer library. It provides mostly the same functionality and perfectly supports TypeScript typings.
This works (no need for Immutable.js):
export type RootState = ReturnType<typeof rootReducer>;
If for some reason it does not works, this one should work:
export type RootState = ReturnType<typeof store.getState>