Comments (15)
If people are still looking at how to get the correct typings for bindActionCreators
when passing in ThunkActions, I've got an open PR to fix this, specifically the line: https://github.com/reduxjs/redux-thunk/pull/224/files#diff-b52768974e6bc0faccb7d4b75b162c99R31
Overloading the function definition and conditionally returning a different object type if the action passed is of type ThunkAction
:
declare module 'redux' {
/**
* Overload for bindActionCreators redux function, returns expects responses
* from thunk actions
*/
function bindActionCreators<M extends ActionCreatorsMapObject<any>>(
actionCreators: M,
dispatch: Dispatch,
): { [N in keyof M]: ReturnType<M[N]> extends ThunkAction<any, any, any, any> ? (...args: Parameters<M[N]>) => ReturnType<ReturnType<M[N]>> : M[N] }
}
Let me know if it fits your needs
from react-redux-typescript-guide.
@rluiten this time I have thoroughly investigated and I found you are right, types are not correct but only for the thunk action creators.
Specifically bindActionCreators could have been augmented by redux-thunk to fix that behaviour.
The types returned from connect should have bound action creators, but it seems they are still typed as thunk action creators so dispatch is not correctly applied.
When I changed mapDispatchToProps declaration to not use bindActionCreators
it's fixed, you can try:
const mapDispatchToProps = (dispatch: Dispatch) => ({
updateRegion: (payload: RegionModel) => dispatch(SitesReducer.updateRegion(payload)),
});
The second one works because this time dispatch is correctly augmented by redux-thunk
typings.
The necessary fix is to augment bindActionCreators
to apply augmented dispatch that can handle thunk actions, but it's not possible with current Type Inference limitations.
from react-redux-typescript-guide.
I freely admit I might have flubbed something.
But it compiles with no errors and appears to work (but that might be pure fluke).
Definition of my Component and its properties.
interface RouteParams {
transitionStatementId: number;
}
export interface OwnProps extends RouteComponentProps<RouteParams> {}
export const mapDispatchToProps = (dispatch: Dispatch<RootState>) =>
bindActionCreators(
{
getTransitionForm
},
dispatch
);
const stateProps = returntypeof(mapStateToProps);
const dispatchProps = returntypeof(mapDispatchToProps);
export type Props = typeof stateProps & typeof dispatchProps & OwnProps;
class TransitionForm extends React.Component<AllProps, OwnState> { /* etc */ }
Inside my components member functions the type of 'props.getTransitionForm` appears to be.
(conveniently visible in VSCode but I did not assume VSCode was correct)
I am calling the action from a submit() function that is part of redux-form.
(params: GetTransitionFormParams) =>
(dispatch: Dispatch<RootState>, getState: () => RootState, extraArgument: any) =>
Promise<any>;
The fire*Action() functions are just examples.
I setup a test and i can use await
it compiles with no errors, and appears to work correctly.
const getPayload = {state, apiUrls, transitionStatementId: 23};
const getResult = getTransitionForm(getPayload);
try {
await getResult;
fireGotAction();
} catch (e) {
fireErrorGotAction();
}
If I use .then() I get a compile error.
The getResult
above gives me the compile error where i try to use .then().
TS2339: Property 'then' does not exist on type 'ThunkAction<Promise<any>, RootState, any>'.
const getPayload = {state, apiUrls, transitionStatementId: 23};
const getResult = getTransitionForm(getPayload);
getResult.then(() => fireGotAction(), () => fireErrorGotAction());
This leads me to believe the types are not really correct, I am not implying they are easy to fix or can be fixed, I fudged the type for myself for now. It appears await isn't enforcing type constraints equivalently to .then()
, and since the underlying value is actually a promise await
works anyway.
Currently i am just casting the property action to any to call then and all seems well with the world.
Thanks for your response, I raised this more to see if it rings a bell with you that might point out something I had missed or possibly even something you can address. I think its complex enough some sort of fix might not be easy and may require much deeper type knowledge than I have, or even typescript may not be able to do express the constraint in its current version.
Thanks,
from react-redux-typescript-guide.
Sorry for the delay responding. It's been a while since I looked at this, but I'll get the conversation started with what I have and see if that's helpful. I'm not totally sure if my code will directly translate, but hopefully, it will be helpful.
type OwnProps = {
foo: string,
};
type ReduxStateProps = {
bar: boolean,
};
type DispatchProps = {
myAC: typeof myAC.bound,
// note the type of myAC is: (x: ArgType) => AbortableAction<FluxAction<void>>
// see below for relevant type definitions of return type
};
type ComponentProps = OwnProps & ReduxStateProps & DispatchProps;
class ComponentFoo extends React.Component<ComponentProps> { // ... }
function mapStateToProps(state: RootState, props: OwnProps): ReduxStateProps {
// ...
return {
bar: true
};
}
function mapDispatchToProps(dispatch: Dispatch<RootState>) {
const acs = {
myAC,
};
return bindActionCreators<typeof acs, DispatchProps>(acs, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(DecisionDetails);
For reference, ReturnType<typeof mapDispatchToProps>
is:
{
myAC: (x: ArgType) => AbortableAction<FluxAction<void>>;
}
The utility types involved are:
export interface AbortableAction<R> extends BluebirdPromise<R> {
abort: () => void;
url: string;
}
export interface FluxAction<Payload> extends Action {
type: string;
payload: Payload;
meta?: any;
error: boolean;
}
export type ActionCreator<Arg, Payload> = {
(a: Arg): FluxAction<Payload>,
type: string,
bound: (x: Arg) => AbortableAction<FluxAction<Payload>>,
arg: Arg,
pl: Payload,
};
Hopefully, that helps. Let me know if there are any questions, and I'll try to answer them.
from react-redux-typescript-guide.
@rluiten hello
EDIT: After writing my post I have noticed that maybe you forgot that you have a thunk action opposed to regular action creator and that is why the resulting value of dispatchProps is wrapped in another function, when you take it out, then everything is correct :)
Original response:
This is how bindActionCreators declaration looks:
export function bindActionCreators<M extends ActionCreatorsMapObject>(actionCreators: M, dispatch: Dispatch<any>): M;
As you can see it will return ActionCreatorsMapObject, so resulting value of dispatchProps is perfectly fine.
Moreover when you check the type of getTransitionForm
prop in the connected component you will find you have exactly the type you have expected after the binding.
This is what I have in my project, the dispatched action is returning a Promise with updated model or undefined, which works exactly as I expect (this is a thunk action, so there is an additional function wrapper):
const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({
updateRegion: SitesReducer.updateRegion,
}, dispatch);
...
const updatedRegion = await this.props.updateRegion(region); // updateRegion: (payload: RegionModel) => (dispatch: Dispatch<RootState>, getState: () => RootState) => Promise<void | RegionModel | undefined>
PS: if your question is resolved, then please mark it closed. Thanks.
from react-redux-typescript-guide.
Awesome, I have learned so much from this, and your answer makes a lot of sense.
Thanks for persisting with this :).
from react-redux-typescript-guide.
@rluiten no problem, me as well learned a new trick :)
I'll add it later to the guide as caveat giving you a well earned credit :)
from react-redux-typescript-guide.
Hi, I just bumped into this issue as well and indeed switching away from bindActionCreators worked. Has anyone posted this to the redux team, to see if they can fix it? I can't find much documentation on this problem other than this thread. thanks
from react-redux-typescript-guide.
Added a new paragraph warning and explaining root case of this issue: https://github.com/piotrwitek/react-redux-typescript-guide#caveat-with-bindactioncreators
from react-redux-typescript-guide.
Possibly helpful to others: I was having this issue as well, but it was resolved once I upgraded @types/react-redux
to v5.0.19.
from react-redux-typescript-guide.
@njgraf512 can you post an example? I still have the issue with @types/react-redux v5.0.20
from react-redux-typescript-guide.
same issue, @njgraf512 updating react-redux typings didn't help and nothing was found in updated package that could help to fix this
from react-redux-typescript-guide.
Maybe we should open a issue on https://github.com/DefinitelyTyped/DefinitelyTyped.
from react-redux-typescript-guide.
The necessary fix is to augment bindActionCreators to apply augmented dispatch that can handle thunk actions, but it's not possible with current Type Inference limitations.
Thought I was going crazy till I found this thread :)
Does this still hold true @piotrwitek?
from react-redux-typescript-guide.
Not sure, It's been a while since I've been using thunks. But type definitions correction for bindActionCreators was merged few days ago, so might be fixed soon reduxjs/redux-thunk#224
from react-redux-typescript-guide.
Related Issues (20)
- VSCode Intellisense broken by RootState HOT 1
- Experiencing a type compilation error when using react-redux connect function for a component that does not inject additional properties into the wrapped base component HOT 11
- Suggestion: Examples for new redux hooks and react-router hooks HOT 2
- Playground fails to compile - import order HOT 1
- Regarding 'Typing connected component with redux-thunk integration' section HOT 1
- Q: how to avoid exposing actionCreators when using redux-thunk
- `bindActionCreators` example is outdated
- src/hoc/connected-with-count.tsx type cast is incorrect
- MapDispatchToProps shorthand HOT 5
- Add new example for non-HOC component that uses connect HOT 2
- Cannot run up
- why the WithConnectedCountUsage component cannot increment the counter?
- 'fc-counter-connected-bind-action-creators.usage' component cannot work HOT 2
- property does not exist on type 'IntrinsicAttributes & Pick<any, symbol>'
- Start playground dir has a error
- Why not use immutable
- Slow typescript compile time HOT 1
- I got parsing error
- Link to missing anchor in the guide HOT 2
- Refactor RenderProps components
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-redux-typescript-guide.