-
Notifications
You must be signed in to change notification settings - Fork 1k
Use with TypeScript 2.0 (@types/redux-thunk) #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I have just realised that I could avoid this whole issue by just calling store.dispatch in my async function :P But it would be good to know what is wrong with the typings / my code. Thanks! :) |
I'm running into the same issue. |
I also don't get the redux-thunk typings to work or just don't get the point. The Dispatch-Definition enforces you to dispatch a ThunkAction. But in Redux with Redux-Thunk Middleware you can either dispatch a classic action (object with ha type property) or a ThunkAction, so the Dispatch typing should support both cases, shouldn't it? |
I have no problem with typescript 2 and @types/redux-thunk since the begining, but I had troubles with the typings definitions when I was using Typescript 1.8. I m not sure to to it the right way, but it works for me (i dont use extra arguments):
You can see a simple example here Please tell me if it helps or if i m doing wrong ! |
In your example you didn't type the dispatch parameter in your thunk action creator. Anyway, I got it working. The problem was my IDE. IntelliJ IDEA doesn't recognize the multiple typings for Dispatch (1 from the redux npm module for classic actions and 1 from the redux-thunk typings for thunk actions). So the IDE showed errors even though the build succeeded. |
Oh ok I understand what you mean, indeed I have the same error. |
As a workaround I made an own type definition file that doesn't cause IDEA to show errors for wrong parameters at Dispatch:
In my application I'm importing Dispatch from "redux-fixed" now, that passes the IDEA error checks. |
I have the same problem, and my build isn't succeeding unlike @Q-Man 's (i.e, it's not an editor problem - my editor, vscode, and build report the same issue). |
Hi, I'm working with [email protected] on vscode and I've encountered the same error report mentioned by @dupski launching an async (redux-thunk) action. Here's the error:
... and here's the action function code (typescript annotations are purposely very lousy):
It seems to me that the issue is related to
Any comments are welcomed and appreciated! |
I think this is the same workaround as mine, but as @Q-Man said, it works because we cast |
@jbcazaux thanks, I got your point! Following your insight and since I'm not returning anything a better code solution in my case would be a
I'm still in my |
I got it working with typed ThunkActions with my solution of adding an own type definition file for the Dispatch Definitions: redux-fixed/index.d.ts:
actions.ts:
|
I am still getting the same error:
with latest @type/redux-thunk any ideas? regards Sean |
@born2net could you please share the function code? |
Until #77 is released, you can just copy the definition from the PR to your project and then tell TS how to find it using path mapping: // typings.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"redux-thunk": ["path/to/definition"]
}
}
} |
I removed redex-thunk from my typings, and added this to my typings.d.ts and still same issue :(
I know it's being applied since if I remove the entire snippet I get many errors on redux, so it is taking it, its just that it does not satisfy this issue of:
regards Sean |
here is my latest and still same issue:
error:
|
Released v2.2.0 with TypeScript definitions included. |
@Q-Man Have you an example on how you use your typed thunk actions in a component with a mapDispatchToProps + bindActionCreators ? I managed to type the thunk actions in my actions module like you but I can't bind them into a |
Am I misunderstanding something, or is it a bit weird that both
|
Having the same issue the line: `DashboardStore.dispatch((dispatch) => { if (response.data) { let notifications = response.data; delete notifications.ResultCode; dispatch({ type: 'STORE_NOTIFICATIONS', notifications: notifications }); } });` |
Hey guys, I've now had way more experienced with TS and have worked out a good way to use the typings that ship with redux-thunk... Basically the trick is to define your thunk function as a The
Heres an example: import { Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import { getStore, IState } from './my_store';
let store = getStore();
// Create myThunkAction function with a type of ThunkAction<R, S, E>
let myThunkAction: ThunkAction<Promise<string>, IState, null> =
(dispatch: Dispatch<IState>, getState: () => IState) => {
return new Promise<string>((resolve, reject) => {
// do async stuff with getState() and dispatch(), then...
resolve('done!');
});
}
store.dispatch(myThunkAction)
.then(() => {
// do stuff after the thunk has finished...
}); Hope this helps folks. Closing this issue now :) |
Heres an example thunk that takes some arguments: // Return a thunk with a type of ThunkAction<R, S, E>
function myThunkAction(someArg: string): ThunkAction<Promise<string>, IState, null> {
return (dispatch: Dispatch<IState>, getState: () => IState) => {
return new Promise<string>((resolve, reject) => {
// do async stuff with someArg, getState() and dispatch(), then...
resolve('done!');
});
};
}
store.dispatch(myThunkAction('www.google.com'))
.then(() => {
// do stuff after the thunk has finished...
}); |
@dupski You don't need to type Dispatch and getState, it's already done par See:
It improves readability :) |
It took me hours to solve it. In my case, the problem was that |
@cr0cK Were you ever able to get this to work with Example:
this works and is completely type-safe However, when you try to map this in a container component:
|
@sarink Yes, you can't use the same props /** action.js **/
import { ThunkAction } from 'redux-thunk';
export interface IItem {
id: string;
}
// use a generic to define the type of the return according to the context (binded action or not)
export type LoadItem<R> = (id: string) => R;
// thunk action with the correct return type
export const loadItem: LoadItem<ThunkAction<<Promise<IItem>, IState, IExtraArgument>>> = (id) => {
return (dispatch, getState) => {
// ...
}
};
/** MyComponent.tsx */
// split your props in order to reuse them
// in mapStateToProps and mapDispatchToProps
export interface IStateProps {
// ...
}
export interface IDispatchProps {
loadItem: LoadItem<Promise<IItem>>;
}
class MyComponent extends React.Component<IProps, {}> {
componentDidMount() {
// the action argument should be checked as a string and item should be an `IItem` object
this.props.loadItem('1').then((item) => {
// ...
});
}
render() {
return <div></div>;
}
}
/** types.d.ts */
// Mapped type (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#mapped-types)
// Use this to check that all functions have been declared in your mapDispatchToProps according
// to the *DispatchProps of your components
declare type ActionCreatorsMapObject<T> = {
[K in keyof T]: any;
}
/** index.js **/
import { IDispatchProps } from './MyComponent';
const mapDispatchToProps = bindActionCreators<ActionCreatorsMapObject<IDispatchProps>>({
loadItem,
// will raise an error if some binds are missing
}, dispatch); |
Your workaround hopefully doesn't work with I haven't yet used this in practice, as almost all thunk actions I am dispatching are functionally /**
* Wrapper used when calling thunk actions that were bound by react-redux's connect.
*
* Usage:
*
* ```ts
* const result = thunkResult(this.props.thunkAction(args))
* ```
*
* TypeScript doesn't support transforming the signature of functions,
* so it's not possible to make a generic type that would correctly
* accept the thunk functions while changing their return type. This has
* to be done with a roundtrip through any.
*
* This is only correct if the action actually was dispatched. By default,
* this will check whether the result is or is not a function to ensure it
* is being used correctly, but if the result really must be a function, the
* second argument can be set to true to disable the check.
*/
export function thunkResult<R> (
thunkAction: ThunkAction<R, any, any>,
resultIsFunction?: true
): R {
const result = thunkAction as any as R
if (typeof result === 'function' && !resultIsFunction) {
throw new Error('thunkResult mistakenly used on undispatched thunk')
}
return result
} |
If anyone is coming here because they just wanted to make a simple import to the store, and import is not working... Here's the solution:
We had to call "default" after each import. Here's the post in Medium |
@superjose - You may want to look into Also worth noting that the behaviour can be impacted by your bundler (webpack, jspm, etc...). |
@atrauzzi Thank you very much for pointing that out. I honestly don't know if it's a problem with my tsconfig or create-react-app typescript. But it is certainly not picking that up: The very first line has allowSyntheticDefaultImports Edit: Thank you! |
In my case upgrading
|
For the love of god, I've been battling with this error for hours:
const verifyUserEmail = (token: string): ThunkAction<Promise<any>, RootState, ApiClient, AnyAction> => {
return async (dispatch, getState, api) => {
dispatch(Actions.verifyUserEmailRequest());
try {
await api.users.verifyUserEmail(token);
return dispatch(Actions.verifyUserEmailSuccess());
} catch (e) {
captureException(e);
if (e.code === 404) {
dispatch(Actions.verifyUserEmailFailure('wrong_token'));
} else if (e.code === 400) {
dispatch(Actions.verifyUserEmailFailure('already_verified'));
}
return dispatch(Actions.verifyUserEmailFailure('some_other_error')); // TODO: types for errors?
}
};
}; I've tried all sorts of combinations.. already on the 4th page of google. So you know. @Redux 4.0 Any ideas, guys? |
// Then you consume it like this:
That's how I got it working! (I honestly didn't know how to quickly rewrite it to the I don't know if that is going to work! If |
Ah, I see. So we're not using any types from redux-thunk?
My question was more related to the type safety
|
@rpmonteiro: exactly!! Now I don't remember where I got the info from. I think it was from a create-react-app-typescript project that was lying around. It was also very painful to get it right. Let me know if that solves the issue! |
I spent most of yesterday battling with this issue, and managed to solve it like so:
In my connected components, instead of using
In this case, I'm using: Hope this helps! :) |
Thank you for taking the time to share this. I actually used the exact same
approach, with the slight tweak of actually overloading redux's dispatch to
take my thunk type.
Was a huge headache.
…On Sat, 9 Jun 2018, 11:34 Shishir Srivastava, ***@***.***> wrote:
I spent most of yesterday battling with this issue, and managed to solve
it like so:
/*
AppAction - extends Redux::Action
AppState - my app's state shape
*/
export type Thunk = ThunkAction<void, AppState, null, AppAction>;
export type Dispatch<S> = ThunkDispatch<S, null, AppAction>;
In my connected components, instead of using Dispatch from redux, I use
the above definition.
const mapDispatchToProps = (
dispatch: Dispatch<AppState>
): ContentOverlayDispatchProps => ({
dismissOverlay: () => dispatch(hideContentOverlay()),
loadContent: (key: string) => dispatch(loadDocument(key))
});
In this case, hideContentOverlay returns an AppAction object, and
loadDocument is a Thunk.
Hope this helps! :)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#103 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHdk51Da-2RkaLfjDgvys58jKlc-WRgaks5t65afgaJpZM4KTSVi>
.
|
@shishir-srivastava What you suggest works with an async function with no parameters but it doesn't if I pass any parameters to an async func. How did you manage? I'm wondering what I'm missing..
This works:
This doesn't:
redux: 4.0.0 |
This seems to work for me: // file: actions/users.ts
import { ActionCreator } from 'redux';
import { ThunkAction } from 'redux-thunk';
export const updateEmail: ActionCreator<
ThunkAction<Promise<UpdateEmailAction>, State, null, UpdateEmailAction>
> = (req: IUpdateEmailRequest) => {
return (dispatch, getState) => {
let action: UpdateEmailAction = {
type: CHANGE_EMAIL,
state: States.INFLIGHT
};
dispatch(action);
return ajax('/api/change-email', {
method: 'POST',
body: JSON.stringify(req)
})
.then(async (resp) => {
if (resp.ok) {
let action: UpdateEmailAction = {
type: CHANGE_EMAIL,
state: States.SYNCED
};
dispatch(action);
return action;
}
let action: UpdateEmailAction = {
type: CHANGE_EMAIL,
state: States.ERRORED
};
dispatch(action);
return action;
})
.catch(() => {
let action: UpdateEmailAction = {
type: CHANGE_EMAIL,
state: States.ERRORED
};
dispatch(action);
return action;
});
};
} I omitted some specifics of my implementation, but this captures the gist of it. I generally return a promise from my async actions, and that promise always resolves to the action that I dispatched. This generally helps me remove some boilerplate state management from components. You could of course use |
For future reference and anyone struggling with complaints about the action creator argument to This is the error I had on
And then some variable complaints, depending on which part of the code I blindly tweaked. Turns out the middleware typing was wrong. This is the correct one (all the other entity types follow the advice in this thread):
|
This approach worked for me:
Dependencies: |
If anyone still here because you can't configure the dispatch to accept thunks: You can configure the generic params of import { logger } from 'redux-logger'
import { applyMiddleware, createStore, combineReducers } from 'redux'
import thunk, { ThunkDispatch } from 'redux-thunk'
const middleware = applyMiddleware<ThunkDispatch<YourState, ThunkThirdParam, Actions>, YourState>(thunk, logger,...) No use of |
I was struggling with this too and passing types to
note: I just tried and we can also pass types to |
I have it working as: import {ThunkDispatch} from 'redux-thunk';
import {Action} from '@reduxjs/toolkit';
import {useDispatch} from 'react-redux';
import {store} from './configureStore';
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = ThunkDispatch<RootState, undefined, Action<string>>;
export const useAppDispatch = () => useDispatch<AppDispatch>(); |
I dont know if this is still relevant but i solved: store.dispatch(INSERT_YOUR_THUNK_ACTION_HERE()) // error by typing the createStore return value: export type appStore = Store<usersState, usersActions>
& { dispatch: ThunkDispatch<usersState, undefined, usersActions>;} // this the good stuff
;
export const configureStore = (usersInitialState: usersState): appStore => {
const appstore = createStore(
usersReducer,
usersInitialState,
applyMiddleware(thunk)
);
return appstore;
}; then you can even drop the type assertion in createStore: const store = createStore(
rootReducer,
applyMiddleware(
thunk as ThunkMiddleware<IState, Actions>, // this is not needed anymore
),
); |
For anyone else having this issue while using redux-toolkit, it could be due to using the spread operator for the middleware. Eg. I started with:
and updated to
https://redux-toolkit.js.org/api/configureStore
https://redux-toolkit.js.org/api/getDefaultMiddleware
|
Uh oh!
There was an error while loading. Please reload this page.
Hi
I'm attempting to use redux-thunk with TypeScript 2.0. The definitions from
npm install @types/redux-thunk
is as follows:The above appears to be completely different the one in the repo ?
I'm creating my store like this:
Then trying to initiate a thunk like this (I've copied the body of the function into the dispatch call for simplicity, it is returned from an action creator in my real code):
Unfortunately the error I get back is:
So it looks like the defs available through npm aren't working (or I am missing something!).
Please could someone confirm:
Thanks guys!!
The text was updated successfully, but these errors were encountered: