I'm having a typing error when calling store.dispatch() with an AsyncThunkAction in my tests. I'm using redux-toolkit. The test will run and work, but TS is not happy.
cognitoConfigSlice.ts
type DispatchExts = ThunkDispatch<RootState, void, AppDispatch> // error here
const middlewares = [thunk]
const mockStore = configureMockStore<LoadConfigState, DispatchExts>(middlewares)
it("creates cognitoConfig/fetch/fulfilled on successful fetch", async () => {
// ...
await store.dispatch(fetchConfig())
const actions = store.getActions()
console.log(actions)
})
Issue
I get the following type error on the type DispatchExts = ThunkDispatch<RootState, void, AppDispatch> line in the test file, with the error specifically on AppDispatch
Type 'ThunkDispatch<{ cognitoConfig: LoadConfigState; }, null, AnyAction> & ThunkDispatch<{ cognitoConfig: LoadConfigState; }, undefined, AnyAction> & Dispatch<...>' does not satisfy the constraint 'Action<any>'.
Property 'type' is missing in type 'ThunkDispatch<{ cognitoConfig: LoadConfigState; }, null, AnyAction> & ThunkDispatch<{ cognitoConfig: LoadConfigState; }, undefined, AnyAction> & Dispatch<...>' but required in type 'Action<any>'.ts(2344)
Source
cognitoConfigSlice.ts
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
// ...
export const fetchConfig = createAsyncThunk<
ConfigPayload,
undefined, // thunk arg is discarded, so not important
{ rejectValue: string }
>("cognitoConfig/fetch", async (_, { rejectWithValue }) => {
try {
const response = await get("/api/config", false)
return response.parsedBody as ConfigPayload
} catch (e) {
return rejectWithValue(`Got error fetching config: ${e}`)
}
})
const cognitoConfigSlice = createSlice({
name: "cognitoConfig",
initialState,
reducers: {},
extraReducers: builder => {
builder.addCase(fetchConfig.pending, state => {
state.status = Status.loading
})
builder.addCase(fetchConfig.fulfilled, (state, action) => {
state.status = Status.succeeded
state.configPayload = action.payload
})
builder.addCase(fetchConfig.rejected, (state, action) => {
state.status = Status.failed
state.errorMessage = action.payload
})
},
})
export type CognitoConfigActions = typeof cognitoConfigSlice.actions
root.ts
import { configureStore } from "@reduxjs/toolkit"
import { useDispatch } from "react-redux"
import cognitoConfigSlice from "./cognitoConfigSlice"
// ...
const store = configureStore({
reducer: {
cognitoConfig: cognitoConfigSlice.reducer,
},
})
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useAppDispatch = () => useDispatch<AppDispatch>()
export default store
Other attempts
I also tried not specifying the types for configureMockStore like so:
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
But it gives me the following error on the fetchConfig() part of ` await store.dispatch(fetchConfig()):
Argument of type 'AsyncThunkAction<ConfigPayload, undefined, { rejectValue: string; }>' is not assignable to parameter of type 'AnyAction'.
Property 'type' is missing in type 'AsyncThunkAction<ConfigPayload, undefined, { rejectValue: string; }>' but required in type 'AnyAction'.ts(2345)