简体   繁体   中英

Redux Thunk with Typescript

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.

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

Not exactly answering the same thing the question was about, but I stumbled upon the same problem using Redux useDispatch() hook. And again not such a good support for the async action types. What I eventualy did was to add an AsyncAction type and created a new hook for the typing:

// hooks.ts

export type AsyncAction = (dispatch: (action: Action) => any) => void;
export type Dispatcher = (action: AsyncAction | Action) => void
export const useAppDispatch: () => Dispatcher = useDispatch as any;

// async-actions.ts

import {AsyncAction} from "./hooks"

export const myAsyncAction: () => AsyncAction = () => (dispatch: (action: 
Action) => any) => {
// async logic with dispatching goes here:
// dispatch(...)
}

//my-component.tsx

import {myAsyncAction} from "./async-actions"
import {useAppDispatch} from "./hooks"

export const MyComponent = () => { 
  const dispatch = useAppDispatch();
  syncHandler () {
    disaptch ({type: MY_SYNC_ACTION})
  }
  asyncHandler () {
    disaptch (myAsyncAction())
  }
  ...
}

Even though a bit Typescrip "hacky" the advantages of this approach are that you get full type check support for the sync and async (Thunk) actions, and from the client (component) point of view there is no difference - no need to use a different type system.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM