How to dispatch an Action or a ThunkAction (in Typ

2019-04-24 18:46发布

Say I have code like so:

import { Action, Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';

interface StateTree {
  field: string;
}

function myFunc(action: Action | ThunkAction<void, StateTree, void>,
                dispatch: Dispatch<StateTree>) {
  dispatch(action); // <-- This is where the error comes from
}

...I get this error from the TypeScript compiler:

ERROR in myFile.ts:x:y
TS2345: Argument of type 'Action | ThunkAction<void, StateTree, void>' is not assignable to parameter of type 'Action'.
  Type 'ThunkAction<void, StateTree, void>' is not assignable to type 'Action'.
  Property 'type' is missing in type 'ThunkAction<void, StateTree, void>'.

I believe the problem is because of the way the redux-thunk type definition file augments the redux Dispatch interface and the inability for TypeScript to know which definition of Dispatch to use.

Is there a way around this?

3条回答
女痞
2楼-- · 2019-04-24 19:01

ThunkAction signature changed with latest version (now is ThunkAction<void, Your.Store.Definition, void, AnyAction>) and unless some evil double casting (action as {} as Action), the more elegant way I found is to define the redux dispatch as a ThunkDispatch like this:

import { applyMiddleware, Store, createStore, AnyAction } from 'redux';
import logger from 'redux-logger';
import thunk, { ThunkDispatch } from 'redux-thunk';

import { Redux } from '../definitions';
import rootReducer from './reducers';
import { bootstrap } from './actions';

export default function configureStore() {

    const middleware = applyMiddleware( thunk, logger );

    const store: Store<Redux.Store.Definition> = createStore(rootReducer, middleware);

    // Here the dispatch casting:
    (store.dispatch as ThunkDispatch<Redux.Store.Definition, void, AnyAction>)( bootstrap() );

    return store;

}

In case someone else is looking for an updated answer! ^^

查看更多
我只想做你的唯一
3楼-- · 2019-04-24 19:02

These are the correct typings: https://github.com/reduxjs/redux-thunk/blob/master/test/typescript.ts

Most notably:

const store = createStore(fakeReducer, applyMiddleware(thunk as ThunkMiddleware<State, Actions>));

applyMiddleware will already override the dispatch with a ThunkDispatch.

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-04-24 19:03

I think you are correct in that despite being able to handle both types, typescript cannot work out which overload to use.

I think the best option for you is to cast back to the desired type when calling dispatch

function myFunc(action: Action | ThunkAction<void, StateTree, void>, 
                dispatch: Dispatch<StateTree>) {
  if (action instanceof ThunkAction<void, StateTree, void>) {
    dispatch(action as ThunkAction<void, StateTree, void>);
  } else {
    dispatch(action as Action);
  }
}

I hope I'm wrong and there is a better way to achieve this.

查看更多
登录 后发表回答