question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Type errors after upgrading to 1.8.1 and Redux 8: Property 'type' is missing in type '(dispatch: AppDispatch) => Promise<void>' but required in type AnyAction

See original GitHub issue

Hi. I’m working on migrating a codebase from React 17 to 18, react-redux 7.2.0 to 8.0.1 and reduxjs/toolkit from 1.7.1 to 1.8.1 and immediately after bumping the packages I get this error:

Argument of type '(dispatch: AppDispatch) => Promise<void>' is not assignable to parameter of type 'AnyAction'.
  Property 'type' is missing in type '(dispatch: AppDispatch) => Promise<void>' but required in type 'AnyAction'.

18     dispatch(acknowledgeTask(taskApi, taskId))
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Picture:

image

The patch notes for 1.8.0 mentions changes to dispatch types based on configureStore middlewares and I found this reply in a similar issue which I fixed (because I had it set up the wrong way as explained there) but it did not have any effect.

The action I’m having problems with is a thunk action

// old version, with redux-thunk

import { ITaskApi } from '@app/api/taskApi'
import type { AppDispatch } from '@app/infrastructure/redux/store'
import { removeStickyTask } from './stickyTasksSlice'
import { showNotification, Severity } from './notificationsSlice'

export const acknowledgeTask =
  (taskApi: ITaskApi, taskId: string) => async (dispatch: AppDispatch) => {
    try {
      await taskApi.acknowledgeTask(taskId)
      dispatch(removeStickyTask({ stickyTaskId: taskId }))
    } catch (err) {
      dispatch(
        showNotification({
          id: `acknowledge_task_${taskId}_failed`,
          message: 'Failed to acknowledge task',
          severity: Severity.error,
        })
      )
    }
  }

After reading more on redux’s documentation I see I could probably refactor this action to use createAsyncThunk instead of the redux-thunk package, and so I did to see if that fixed the typing:

// new version, with createAsyncThunk

export interface AcknowledgeTaskArgs { taskApi: ITaskApi, taskId: string }

export const acknowledgeTask = createAsyncThunk(
  'stickyTasks/acknowledge',
  async (args: AcknowledgeTaskArgs, thunkApi) => {
  const { taskApi, taskId } = args
  const { dispatch } = thunkApi

  try {
      await taskApi.acknowledgeTask(taskId)
      dispatch(removeStickyTask({ stickyTaskId: taskId }))
    } catch (err) {
      dispatch(
        showNotification({
          id: `acknowledge_task_${taskId}_failed`,
          message: 'Failed to acknowledge task',
          severity: Severity.error,
        })
      )
    }
})

No changes to the error message really.

After looking more on the Redux Toolkit docs for createAsyncThunk I found this strange because there’s not really many differences in the doc’s example and my code in how redux is set up and used.

So I ported the documentation example for createAsyncThunk to a sandbox and got the same type error there, along with some other type errors: https://codesandbox.io/s/adoring-microservice-sdyijf?file=/src/Demo.tsx:181-215. There are type erros in Demo.tsx (this one is the same type error I get in my other project), action.ts and store.ts.

It therefore seems to me like the changes to the typing of dispatch and configureStore is broken when the example code produces the same error I have in my code, and I’m therefore not sure how to proceed or fix this.

For completeness, here is my app code:

// store.ts

import { configureStore } from '@reduxjs/toolkit'
import createSagaMiddleware from 'redux-saga'
import reducers from '@app/globalState/reducers'
import sagas from '@app/globalSideEffects/sagas'

const sagaMiddleware = createSagaMiddleware()

export const store = configureStore({
  reducer: {
    ...reducers,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({ serializableCheck: false }).concat(sagaMiddleware),
})

sagas.forEach(sagaMiddleware.run)

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
// taskActions.ts, with old and new code

import { createAsyncThunk } from '@reduxjs/toolkit'
import { ITaskApi } from '@app/api/taskApi'
// import type { AppDispatch } from '@app/infrastructure/redux/store'
import { removeStickyTask } from './stickyTasksSlice'
import { showNotification, Severity } from './notificationsSlice'

// export const acknowledgeTask =
//   (taskApi: ITaskApi, taskId: string) => async (dispatch: AppDispatch) => {
//     try {
//       await taskApi.acknowledgeTask(taskId)
//       dispatch(removeStickyTask({ stickyTaskId: taskId }))
//     } catch (err) {
//       dispatch(
//         showNotification({
//           id: `acknowledge_task_${taskId}_failed`,
//           message: 'Failed to acknowledge task',
//           severity: Severity.error,
//         })
//       )
//     }
//   }

export interface AcknowledgeTaskArgs { taskApi: ITaskApi, taskId: string }

export const acknowledgeTask = createAsyncThunk('stickyTasks/acknowledge', async (args: AcknowledgeTaskArgs, thunkApi) => {
  const { taskApi, taskId } = args
  const { dispatch } = thunkApi

  try {
      await taskApi.acknowledgeTask(taskId)
      dispatch(removeStickyTask({ stickyTaskId: taskId }))
    } catch (err) {
      dispatch(
        showNotification({
          id: `acknowledge_task_${taskId}_failed`,
          message: 'Failed to acknowledge task',
          severity: Severity.error,
        })
      )
    }
})
// StickyTasksContainer.tsx, where the action is dispatched and the type error occurs.

import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { acknowledgeTask } from '@app/globalState/stickyTasksActions'
import { RootState } from '@app/infrastructure/redux/store'
import { useTaskApi } from '@app/api/taskApiHook'
import { useAuthenticatedUser } from '@app/components/AuthenticationBoundary'
import StickyTasks from './StickyTasks'

function StickyTasksContainer(): JSX.Element {
  const dispatch = useDispatch()
  const stickyTasks = useSelector((state: RootState) => state.stickyTasks)
  const user = useAuthenticatedUser()
  const taskApi = useTaskApi(user.accessTokenRaw)

  function onTaskClosed(taskId: string) {
    dispatch(acknowledgeTask({ taskApi, taskId }))
  }

  return <StickyTasks tasks={stickyTasks} onTaskClosed={onTaskClosed} />
}

export default StickyTasksContainer

Any advice or thoughts would be appreciated, thanks 😃

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
phryneascommented, Aug 29, 2022

@lfb please don’t do that but follow the TypeScript Quickstart guide that has already been linked in this issue to create a useAppDispatch hook.

1reaction
lfbcommented, Aug 29, 2022

solution:

import { useDispatch } from "react-redux";

export type AppDispatch = typeof store.dispatch; 
const dispatch: (...args: unknown[]) => Promise<User> = useDispatch<AppDispatch>();
Read more comments on GitHub >

github_iconTop Results From Across the Web

How do I resolve 'Property 'type' is missing in ... - Stack Overflow
I still saw the type error after declaring dispatch as AppDispatch because I used the spread operator to define the store's middleware option....
Read more >
React-Redux v8.0.0: React 18 support, TS conversion ... - Reddit
Property 'type' is missing in type '(dispatch: Dispatch<SomeAction>) => Promise<void>' but required in type 'AnyAction'.
Read more >
Redux Toolkit TypeScript Quick Start
How to set up and use Redux Toolkit and React-Redux with TypeScript. ... While it's possible to import the RootState and AppDispatch types...
Read more >
Accessing Global State inside of Async Thunks with TypeScript
If we really want to be thorough though, we can pass in the full types like this: ... Create a Reducer with Redux...
Read more >
cannot read properties of undefined (reading 'type') redux
You should pass the type inside your actions to the reducer. as you see the error says property type is not defiend ....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found