I am creating a web application in which I am using firebase as a database, I am using redux and typescript. I made the dispatch inside a callback like this:
export const uploading=(direction:string)=>{
return async(dispatch:Dispatch,getState:()=>State)=>{
const {active} = getState().dates;
const ss = await getSS(direction);
active.home = ss;
dispatch(save(active));
};
};
and the error I get is the following:
Argument of type '(dispatch: Dispatch, getState: () => State) => Promise<void>' is not assignable to parameter of type 'AnyAction'. Property 'type' is missing in type '(dispatch: Dispatch, getState: () => State) => Promise<void>' but required in type 'AnyAction'.
and the function that appears in the dispatch is the following:
export const save = (dates:Dates) => {
return async(dispatch:Dispatch,getState:()=>State) => {
const { uid } = getState().auth;
const dateToSave = {...date,id:""};
const dateToFirestore = doc(db,`${uid}/dates/${dates.id}`);
try{
await updateDoc(dateToFirestore,dateToSave);
dispatch(refreshDate(date.id,date));
console.log("ok")
}catch(error){
console.log(error)
}
};
};
Now, if I don't do the dispatch from an async function I don't have any problem, in fact I was already doing it to save new data, but when I try to call it from the aforementioned function I get the error.
My store
import {combineReducers,compose,createStore,applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import {authReducer} from '../reducers/authReducer';
import {uiReducer} from '../reducers/uiReducer';
import {datesReducer} from '../reducers/datesReducer';
const reducers = combineReducers({auth: authReducer,ui: uiReducer,dates: datesReducer});
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__||compose;
export const store = createStore(
reducers,
composeEnhancers(applyMiddleware(thunk))
);
I want to add some information, I tell you, if I dispatch a normal Action there is no problem, that is, an action that does not return an async function
CodePudding user response:
From redux
store.ts
import { AnyAction } from 'redux';
return async(dispatch: Dispatch<AnyAction>, getState: () => State)
// rest of your code
or using ThunkDispatch
imported from redux-thunk
import { AnyAction } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
// Types to cut down on boilerplate across dozens of thunks.
type Dispatcher = ThunkDispatch<State, undefined, AnyAction>;
type GetState = () => State;
return async(dispatch: Dispatcher , getState: GetState)
// rest of your code
Here is a few thoughts of redux maintainer on writing typescript
It feels like a number of TS users would rather spend hours trying to come up with unreadable and incredibly complex type declarations, rather than solving real problems and shipping code that does something useful
I think its true when we first time do typescript, slap it with any
^^ mark it with FIXME and move on to next task
CodePudding user response:
Especially when using TypeScript, you should be using the official Redux Toolkit. Even the JS code gets cut at least in half, but you save almost all of the TS type declarations traditional Redux would have.
Also, and that is more to the point of this question, there is explicit documentation on how to set that up to be used with TypeScript, including defining specific useAppDispatch
hooks that take the types of all Redux middleware (including thunk) into account.
In this case:
import { configureStore } from '@reduxjs/toolkit'
import { useDispatch } from 'react-redux'
import rootReducer from './rootReducer'
const store = configureStore({
reducer: rootReducer,
})
export type AppDispatch = typeof store.dispatch // you can use this Dispatch type in your thunks
export const useAppDispatch = () => useDispatch<AppDispatch>() // Export a hook that can be reused to resolve types
export default store