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 issueHi. 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:
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:
- Created a year ago
- Comments:6 (2 by maintainers)
@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.solution: