Why am I getting the error message "Property 'then' does not exist on type 'AsyncThunkAction'"?

Viewed 12113

I can't seem to receive a Promise from createAsyncThunk function from Redux-toolkit I'm fairly new to Typescript and I'm struggling to figure out why it's giving me Property 'then' does not exist on type 'AsyncThunkAction<Student, number, {}>' error even though the promise does get returned if I remove the typing. Here is my createAsyncThunk f-n

export const getStudentByIdRequest = createAsyncThunk<Student, number>(
  'student/getStudentByIdRequest',
  async (id, { rejectWithValue }) => {
    try {
      const { data } = await instance.get(`student/${id}/`)
      return data
    } catch (err) {
      let error: AxiosError = err
      if (error) {
        return rejectWithValue({
          message: `Error. Error code ${error.response?.status}`,
        })
      }
      throw err
    }
  }
)

And that is how I dispatch it from my React component

dispatch(getStudentByIdRequest(userId)).then((res) => console.log(res))

The error appears where I try to call then on the thunk

3 Answers

Your dispatch does not take types for thunks into account and thus the return type is typed incorrectly. Please use the actual Dispatch type from the store as decsribed in the documentation:

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
export const useAppDispatch = () => useDispatch<AppDispatch>() // Export a hook that can be reused to resolve types

and then use useAppDispatch instead of useDispatch in your component.

Another potential solution for this could be using ThunkDispatch type instead of plain Dispatch, as plain Dispatch is not meant to be handling async stuff.

Defining reusable useAppThunkDispatch hook in store.ts:

import { Action, ThunkDispatch, configureStore } from '@reduxjs/toolkit';

export const store = configureStore({
    reducer: {
        blog: blogSlice,
    },
});

export type RootState = ReturnType<typeof store.getState>;

export type ThunkAppDispatch = ThunkDispatch<RootState, void, Action>;

export const useAppThunkDispatch = () => useDispatch<ThunkAppDispatch>();

You can then use useAppThunkDispatch hook in your app just like useAppDispatch or useDispatch hook.

The issue I was facing was very similar to this, I was working on something based on the Redux Toolkit documentation and the following simply didn't work:


let dispatch = useDispatch()

The point was that the tutorial uses the useDispatch() on a personalized hook, which is exported as useAppDispatch()

import { useAppDispatch } from "app/hooks";

If you use the right importation and types you're gonna be able to solve this issue.

Related