Search code examples
reactjstypescriptredux

Error in dispatch async function is not assignable to parameter of type Anyaction in React, Typescript, Redux


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


Solution

  • 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