Type casting dispatch for configureMockStore from createAsyncThunk

Viewed 389

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)
0 Answers
Related