reduxreact-reduxredux-thunkredux-toolkitthunk

Improper type signature for `dispatch` method despite using "app dispatch" hook


Introduction

I'm using Redux Toolkit to add Redux support to a React application served by a Django app. We're using Typescript, and so we're following the Typescript Quick Start from the Redux Toolkit docs.

An important element of using Redux (Toolkit?) with Typescript is to ensure that your dispatch(...) method has the correct type signature. As described in the docs, if you simply use the useDispatch(...) hook from react-redux,

the default Dispatch type does not know about thunks. In order to correctly dispatch thunks, you need to use the specific customized AppDispatch type from the store that includes the thunk middleware types, and use that with useDispatch. Adding a pre-typed useDispatch hook keeps you from forgetting to import AppDispatch where it's needed.

That's fine, and I followed those instructions. My code exports a new hook, just like the tutorial:

export type AppDispatch = typeof store.dispatch;
export const useAppDispatch = () => useDispatch<AppDispatch>();

My problem is: when I use that hook, the type signature for the dispatch(...) method still doesn't accept thunks. The following code:

const dispatch = useAppDispatch();
dispatch(customAction({ ... params ... }));

Produces a compilation error:

ERROR in [at-loader] ./src/components/Widget.tsx:45:9 
TS2345: Argument of type 'AsyncThunkAction<void, CustomActionParams, {}>' is not assignable to parameter of type 'AnyAction'.
Property 'type' is missing in type 'AsyncThunkAction<void, CustomActionParams, {}>' but required in type 'AnyAction'.

My question: Why isn't the typed dispatch method correctly accepting AsyncThunkActions?

Things I've Tried

Interestingly, calling dispatch(...) with the AppDispatch type explicitly parameterized results in the same error. Only parameterizing dispatch(...) with any silences the error, which obviously isn't ideal.

const dispatch = useAppDispatch();
dispatch<AppDispatch>(customAction({ ... params ... })); // same error
dispatch<any>(customAction({ ... params ... })); // error silenced

This makes me think that the issue is AppDispatch not correctly inferring that it should take AsyncThunkAction types, which should happen automatically. Something that could be causing this is that my async action is defined within extraReducers, like so:

export const customAction = createAsyncThunk(
    "slice/customAction",
    async (payload: CustomActionParams) { ... }
);

export const slice = createSlice({
    name: "slice",
    initialState,
    reducers: {},
    extraReducers: (builder) => {
         builder.addCase(customAction.fulfilled, (state, action) => { ... });
    }
});

I'm not sure why this wouldn't cause the type to update, but it's something I've got to resolve.

Differences from standard setup

A few things about my environment could also theoretically contribute to this issue, so I'm including them here for correctness:

Questions that are not duplicates:


Solution

  • This issue was ultimately caused by some sort of version mismatch between the react-redux and @reduxjs/toolkit packages. I removed my yarn.lock and deleted my node_modules, and reinstalled from scratch, and the issue disappeared!

    (Additionally, I also had to pin TypeScript at ~4.1.5 due to a separate issue installing TypeScript with Yarn 2.)