redux-thunk: TypeScript Error in Middleware
The overloading of Dispatch
by redux-thunk
breaks middlewares that only handle standard action objects (as apposed to thunks).
Example:
import {Action, Dispatch, Middleware, Store} from 'redux';
import {IAppState} from '../reducers';
export const middleware: Middleware = (store: Store<IAppState>) => (next: Dispatch<IAppState>) => (action: Action) => {
// Do something with the action ...
next(action);
};
The resulting error is:
Type '(store: Store<IAppState>) => (next: Dispatch<IAppState>) => (action: Action) => void' is not assignable to type 'Middleware'.
Type '(next: Dispatch<IAppState>) => (action: Action) => void' is not assignable to type '(next: Dispatch<any>) => Dispatch<any>'.
Type '(action: Action) => void' is not assignable to type 'Dispatch<any>'.
Types of parameters 'action' and 'asyncAction' are incompatible.
Type '(dispatch: Dispatch<any>, getState: () => any, extraArgument: any) => any' is not assignable to type 'Action'.
Property 'type' is missing in type '(dispatch: Dispatch<any>, getState: () => any, extraArgument: any) => any'.
A possible fix to remove the compiler error would be to declare a union type for the Action, i.e. Action | Redux.ThunkAction<any, IAppState, any>
:
export const middleware: Middleware = (store: Store<IAppState>) => (next: Dispatch<IAppState>) => (action: Action | Redux.ThunkAction<any, IAppState, any>) => {
// Do something with the action ...
next(action as Action);
};
But this is incorrect if your middleware only handles Action
!
The better solution would be to declare a Dispatch
interface within the redux-thunk
module that extends Redux.Dispatch
. This Dispatch
could then be used in action creators that return a ThunkAction
:
import {IAppState} from '../reducers';
import {ThunkAction, Dispatch} from 'redux-thunk';
export function thunkedActionCreator(): ThunkAction<void, IAppState, void> {
return (dispatch: Dispatch<IAppState>, getState: () => IAppState): void => {
// Do something async and dispatch actions or other thunks ...
};
}
Middlewares on the other hand would use Redux.Dispatch
(see middleware example above).
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 3
- Comments: 37
Commits related to this issue
- declare own Dispatch and Store interfaces The current implementation of the typings makes it impossible to create a middleware that only handles standard actions. This means a middleware must handle ... — committed to unstubbable/redux-thunk by deleted user 8 years ago
- declare own Dispatch and Store interfaces The current implementation of the typings makes it impossible to create a middleware that only handles standard actions. This means a middleware must handle ... — committed to unstubbable/redux-thunk by deleted user 8 years ago
I think the original issue can be resolved with improved typings based on https://github.com/reactjs/redux/pull/2563 which hopefully lands soon.
not sure if u r into ng2, but if u r: Angular 2 Kitchen sink: http://ng2.javascriptninja.io and source@ https://github.com/born2net/Angular-kitchen-sink Regards,
Sean
IMO is not a proper picture. Consider these:
Where should the
Store
come from? the order of the middleware should have nothing to do with where you get theStore
from. That’s why it is an augmentation.I can understand what is your confusion.
If it is written in typescript, you would do module augmentation. And the
Store
is still imported fromredux
instead ofredux-thunk
.If it follows your implementation, then other packages which augment
Dispatch
would need to do the same thing. If user wants to use bothredux-thunk
andredux-promise
, where should he/she gets theStore
from?Well, I think that’s a problem.
Store
does not belongs toredux-thunk
, so we should not export and require user to importStore
fromredux-thunk
.Think about it this way: If
redux
andredux-thunk
are written in TS to begin with, what should have happened? It is an augmentation of a method and should be remain as so.My two cents, 🌷