redux-thunk: ThunkAction is not assignable to parameter of type 'AnyAction'.

Bug Report

Package name / version

redux-thunk@2.4.1

Description

I am trying to use a simple method from my store:

store.dispatch(ThunkAction);

It is working on run time, but I am receiving an error message on Typescript:

TS2345: Argument of type 'ThunkAction<Promise<AuthorizationDto | null>, State, unknown, SetAuthorizationAction>' is not assignable to parameter of type 'AnyAction'.   Property 'type' is missing in type 'ThunkAction<Promise<AuthorizationDto | null>, State, unknown, SetAuthorizationAction>' but required in type 'AnyAction'. 

I already tried to import the extend-redux like that:

import 'redux-thunk/extend-redux';

But the problem is the run time does not find file =S.

Screen Shot 2022-04-13 at 3 36 16 PM

I already tried every single solution that’s I found on the previous issues, but non of them worked for me.

Steps to reproduce

  • Install the redux-thunk using “npm install”
  • Create a ThunkAction
  • Call the store.dispatch(ThunkAction)
  • See typescript Type error

Expected behavior

No error message from typescript when using store.dispatch(ThunkAction)

Environment

  • OS: macOS Monterey 12.3.1
  • Node/npm version: node v16.14.2 / npm 8.5
  • Platform: React Native iOS/Android

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 17
  • Comments: 46 (25 by maintainers)

Commits related to this issue

Most upvoted comments

FWIW, I believe the reason this is coming up as an issue with react-redux v8 is because the v7 useDispatch() was typed as:

// NOTE: the first overload below and note above can be removed if redux-thunk typings add an overload for
// the Dispatch function (see also this PR: https://github.com/reduxjs/redux-thunk/pull/247)
export function useDispatch<TDispatch = Dispatch<any>>(): TDispatch;
export function useDispatch<A extends Action = AnyAction>(): Dispatch<A>;

The first function overload means you can dispatch literally anything (as a workaround for redux-thunk).

But in v8 it’s now typed as:

export declare const useDispatch: <AppDispatch extends Dispatch<AnyAction> = Dispatch<AnyAction>>() => AppDispatch;

which only allows for Action objects.

So this issue isn’t “new” it’s just been masked by the loose types in the old react-redux type definitions.


That’s just background for why this is coming up now. If you’re hitting this error now as a user you should either:

  • Use Redux Toolkit and define typed hooks (which will be correctly typed and allow thunk actions)
  • If you’re using vanilla Redux, most bundlers won’t like import 'redux-thunk/extend-redux' in a regular TypeScript file because they think you’re trying to import JavaScript so you can either:
    • Use import type {} from 'redux-thunk/extend-redux'
    • Put /// <reference types="redux-thunk/extend-redux" /> in a .d.ts file that’s included in your type-checking
    • Put import 'redux-thunk/extend-redux' in a .d.ts file that’s included in your type-checking
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import { AnyAction, combineReducers } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
 
const rootReducers = combineReducers();

type AppState = ReturnType<typeof rootReducers>;

type TypedDispatch<T> = ThunkDispatch<T, any, AnyAction>;
 
export const useAppDispatch = () => useDispatch<TypedDispatch<AppState>>();

export const useAppSelector: TypedUseSelectorHook<AppState> = useSelector;

// USE
const dispatch = useAppDispatch();

const state = useAppSelector((state: AppState) => state.xxx);

@Methuselah96’s solution pointed me in the right direction but since redux-thunk/src/types.ts currently has a typescript error which caused my pipelines to fail, I created a redux-thunk.d.ts file:


// This is required to fix redux thunk errors introduced with react-redux version 8
import 'redux'

declare module 'redux' {
    /**
     * Overload for bindActionCreators redux function, returns expects responses
     * from thunk actions
     */
    function bindActionCreators<
        ActionCreators extends ActionCreatorsMapObject<any>
    >(
        actionCreators: ActionCreators,
        dispatch: Dispatch
    ): {
        [ActionCreatorName in keyof ActionCreators]: ReturnType<
            ActionCreators[ActionCreatorName]
        > extends ThunkAction<any, any, any, any>
            ? (
                  ...args: Parameters<ActionCreators[ActionCreatorName]>
              ) => ReturnType<ReturnType<ActionCreators[ActionCreatorName]>>
            : ActionCreators[ActionCreatorName]
    }

    /*
     * Overload to add thunk support to Redux's dispatch() function.
     * Useful for react-redux or any other library which could use this type.
     */
    export interface Dispatch<A extends Action = AnyAction> {
        <ReturnType = any, State = any, ExtraThunkArg = any>(
            thunkAction: ThunkAction<ReturnType, State, ExtraThunkArg, A>
        ): ReturnType
    }
}


@Methuselah96’s solution pointed me in the right direction but since redux-thunk/src/types.ts currently has a typescript error which caused my pipelines to fail, I created a redux-thunk.d.ts file:

// This is required to fix redux thunk errors introduced with react-redux version 8
import 'redux'

declare module 'redux' {
    /**
     * Overload for bindActionCreators redux function, returns expects responses
     * from thunk actions
     */
    function bindActionCreators<
        ActionCreators extends ActionCreatorsMapObject<any>
    >(
        actionCreators: ActionCreators,
        dispatch: Dispatch
    ): {
        [ActionCreatorName in keyof ActionCreators]: ReturnType<
            ActionCreators[ActionCreatorName]
        > extends ThunkAction<any, any, any, any>
            ? (
                  ...args: Parameters<ActionCreators[ActionCreatorName]>
              ) => ReturnType<ReturnType<ActionCreators[ActionCreatorName]>>
            : ActionCreators[ActionCreatorName]
    }

    /*
     * Overload to add thunk support to Redux's dispatch() function.
     * Useful for react-redux or any other library which could use this type.
     */
    export interface Dispatch<A extends Action = AnyAction> {
        <ReturnType = any, State = any, ExtraThunkArg = any>(
            thunkAction: ThunkAction<ReturnType, State, ExtraThunkArg, A>
        ): ReturnType
    }
}

it worked just fine! thank you very much!

@markerikson I transferred the pluggable middlewares from .prepend([]) to .concat(middleware1, middleware2, ...) or .concat([middleware1, middleware2, ...]) and the type error disappeared. Thank you very much for your help! 👍🏻

@sevgeek : I think the issue here is the use of .prepend([SomeMiddleware]), and more specifically, the use of an array as the argument.

If I uncomment that API slice reducer, and then remove the square brackets from both the .prepend and .concat lines, the AppDispatch type looks to be correct.

We do some complex types manipulation to figure out how middleware might alter the type of store.dispatch, and it looks like that just doesn’t work right if you pass in an array as an argument. (In the case where you wanted to add multiple middleware at once, you pass them in as separate args, like .concat(middleware1, middleware2).)

For me import 'redux-thunk/extend-redux'; was causing a Webpack error:

ERROR in ./source/scripts/app.tsx 5:0-34
Module not found: Error: Can't resolve 'redux-thunk/extend-redux' in 'C:\Users\nbier\Documents\test-app'

I ended up using an empty type-import to clue Webpack into the fact I wasn’t trying to import a JS module:

import type {} from 'redux-thunk/extend-redux';

@pailhead I’m not asking about “why” you’re trying to do this - I’m telling you how to fix it 😃

How are you dispatching it? If you’re using useDispatch make sure you’re using a typed hook.

@mendesbarreto unfortunately I don’t know what the ThunkAction variable looks like in this example, or how the middleware was set up, or what TS version you’re using, or how TS itself is configured. So, I really need to see an actual project if at all possible, so I can investigate it myself.