Warm tip: This article is reproduced from stackoverflow.com, please click
javascript reactjs typescript redux

Redux Thunk with Typescript

发布于 2020-03-27 10:23:13

I am learning Typescript and I am trying to implement a simple React/Redux app. When I use sync actions it works fine, but the problems are with the async action. I am following the official redux tutorial.

First I declare the state for the session

export interface UserSessionState {
  loggedIn: boolean;
}

Then I declare the interface for the action

interface UpdateSessionAction {
  type: 'USER_LOGIN';
  payload: boolean;
}

I export them with Union Types

export type UserActionTypes = UpdateSessionAction;

Then I have the actual Action


export function updateSession(loggedIn: UserSessionState) {
  return {
    type: 'USER_LOGIN',
    payload: loggedIn,
  };
}

I have a fake api call

function api() {
  return Promise.resolve(true);
}

And finally the login

export const userLogin = (): ThunkAction<
  void,
  {},
  {},
  AnyAction
> => async (dispatch: ThunkDispatch<{}, {}, AnyAction>) => {
  const res = await api();
  dispatch(updateSession({ loggedIn: res }));
};

In the reducer I simply initialize the state

initialState: UserSessionState = {loggedIn: false}

Then I do the normal redux stuff for the reducer.

Finally in my store I call the initial action for checking the state

store.dispatch(userLogin());

I keep getting this error:

Argument of type 'ThunkAction<Promise<void>, {}, {}, AnyAction>' is not assignable to parameter of type 'AnyAction'.
  Property 'type' is missing in type 'ThunkAction<Promise<void>, {}, {}, AnyAction>' but required in type 'AnyAction'.

I am missing a type but I have no idea what I do wrong.

Questioner
Kaiser Soze
Viewed
145
yuval.bl 2019-07-04 00:03

In short:

You get this error because what returned from your userLogin() function is a ThunkAction, which is missing type

Why this is happening?

dispatch should accept parameter of type AnyAction. AnyAction is a redux type, which extends Action (which have a mandatory property type).

This is from the current redux types file

export interface Action<T = any> {
  type: T
}

/**
 * An Action type which accepts any other properties.
 * This is mainly for the use of the `Reducer` type.
 * This is not part of `Action` itself to prevent users who are extending `Action.
 */
export interface AnyAction extends Action {
  // Allows any extra properties to be defined in an action.
  [extraProps: string]: any
}

How to fix it? Use ThunkDispatch type instead of redux's standard Dispatch. The following example and more can be found on this Gist

const mapDispatchToProps = (dispatch: ThunkDispatch<MyState, void, Action>) => {
  return {
    onRequestClick: (arg: any) => dispatch(myAsyncAction(arg)),
  };
}

Also, see this article, section Map Dispatch to Props