2
votes

I'm trying to create an async action with redux-thunk. It almost works but the only problem is dispatch(f()) causes error in TSC.

As reading redux official document, it accepts functions.

The code is here:

import { applyMiddleware, createStore, Reducer } from 'redux';
import thunkMiddleware, { ThunkAction } from 'redux-thunk';

// --------------------------------
// State

export interface IAppState {
  active: boolean;
}
const initialAppState: IAppState = {
  active: false,
};

// --------------------------------
// Actions and action creators

type AppAction = { type: 'turnOn' } | { type: 'turnOff' };

function turnOn (): AppAction {
  return { type: 'turnOn' };
}

function turnOff (): AppAction {
  return { type: 'turnOff' };
}

// --------------------------------
// Reducers

const rootReducer: Reducer<IAppState, AppAction> = (
  state = initialAppState,
  action,
) => {
  switch (action.type) {
    case 'turnOn': return { ...state, active: true };
    case 'turnOff': return { ...state, active: false };
    default: return state;
  }
};

// --------------------------------
// Store

export function createAppStore () {
  return createStore<IAppState, AppAction, {}, {}>(
    rootReducer,
    applyMiddleware(thunkMiddleware),
  );
}

const store = createAppStore();

// --------------------------------
// Use store

store.dispatch(turnOn());
store.dispatch(turnOff());

// --------------------------------
// Thunk action

function turnOnAndOff (
  delay: number,
): ThunkAction<Promise<void>, IAppState, null, AppAction> {
  return (dispatch) => new Promise((resolve) => {
    dispatch(turnOn());
    setTimeout(() => {
      dispatch(turnOff());
      resolve();
    }, delay);
  });
}

store.dispatch(turnOnAndOff(1000)); // ERROR

In the last line, TSC says their types do not match.

TypeScript error: Argument of type 'ThunkAction< Promise< void>, IAppState, null, AppAction>' is not assignable to parameter of type 'AppAction'.
Property 'type' is missing in type 'ThunkAction< Promise< void>, IAppState, null, AppAction>' but required in type '{ type: "turnOff"; }'. TS2345

If I wrote turnOnAndOff(1000) as any instead, it works correctly.

How to let dispatch() accept the function?

1

1 Answers

4
votes

Dispatching thunk actions using store.dispatch is not supported by the current redux-thunk typings. Usually you would have a mapDispatchToProps where you could type the dispatch as ThunkDispatch. You can do an inline cast even though it is ugly and casting loses type-safety. See this answer: How to dispatch an Action or a ThunkAction (in TypeScript, with redux-thunk)?