-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
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
TypeScript definitions improvements #1526
Conversation
@@ -75,6 +75,10 @@ export function combineReducers<S>(reducers: ReducersMapObject): Reducer<S>; | |||
|
|||
/* store */ | |||
|
|||
export interface MiddlewareDispatch { | |||
<TMiddlewareAction, TMiddlewareActionResult>(action: TMiddlewareAction): TMiddlewareActionResult; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it will not infer types automatically. can you define the function that will not require providing types explicitly?
If I call it without types, TS will infer {}
as a TMiddlewareAction
.
@Igorbek , I don't think it's possible to infer the types here unless you know exactly what middlewares you added. That's runtime behavior. Just like my comparison with |
You know what you can expect from dispatch if you know what configuration to use. export interface Dispatch {
(action: Action): Action;
} So then you have no choice but using this signature. module "redux" { // module augmentation
export interface Dispatch { // interface augmentation
(actionCreator: (dispatch: Dispatch) => void): Promise<any>; // whatever it returns
}
} So then you can you any of signatures were defined. I believe, TS definition for thunk should be in its package. |
I forgot, it takes module "redux" { // module augmentation
export interface Dispatch { // interface augmentation
(actionCreator: (dispatch: Dispatch, getState: () => any) => void): Promise<any>; // whatever it returns
}
} If we define module "redux" { // module augmentation
export interface Dispatch<TState> { // interface augmentation
(actionCreator: (dispatch: Dispatch, getState: () => TState) => void): Promise<any>; // whatever it returns
}
} And then store must refer to its's state type in |
Ok, I've found what it returns. So the thunks's signature would be: module "redux" {
export interface Dispatch<TState> {
<TResult>(asyncAction: (dispatch: Dispatch, getState: () => TState) => TResult): TResult;
}
} |
I've added PR with my thoughts to your PR use-strict#1 :) |
@Igorbek , any ideas about the |
@use-strict for me, export type StoreEnhancerStoreCreator<S> = (reducer: Reducer<S>, initialState: S) => Store<S>;
export type StoreEnhancer<S> = (next: StoreCreator) => StoreEnhancerStoreCreator<S>; As you suggested, a typed version of |
My PR is ready to merge. However the reviewers have asked a few questions which I answered, but didn't hear back from them that is enough or if they have some other concerns. |
@Igorbek I meant another PR that you mentioned above, with changes to |
Oh. I've completely forgot about it and misunderstood you meant it. It wouldn't take too much to do this, but I can do it in evening only (it's morning now for me). So, optimistically, with one day review from you guys, it takes 2 days in total. I know you want to release new features and it might delay, does it work for you? |
Out in 3.4.0. |
This PR follows #1413. I will open up some wounds here, so please excuse me if I missed any of the points in the previous conversation.
Signature of dispatch
The problem that I still have is with the signature of
dispatch
.any
just isn't type-safe at all. It will propagate silently in the app without the developer even realizing. w.r.t what @Pajn and @joshuacc said, there is a difference between consciously making a choice to type-cast and gettingany
by default. With this in mind, it's even better to use{}
instead ofany
(which btw is what type parameters default to anyway).Given the nature of
dispatch
and it being wrapped by middlewares, it isn't possible to properly type it to account for every possibility. (goes with what @xogeny said in previous PR) The default behavior should be to receiveAction
and returnAction
. When middlewares are involved, the middleware decides what the action is and what is returned. Unless someone finds of a way to augment the dispatch signature to work auto-magically with specific middlewares, I think it's better to let the user cast explicitly, because it is something known only by him, given the combination of middlewares that he applied.I understand that explicit cast is more verbose and some may even be tempted to say it's even annoying, but think of it this way: it isn't any different than using
Promise
orMap
orSet
. Only the user know what exactly he's dispatching and what he expects to be returned.Signature of StoreCreator and StoreEnhancer
I'm not sure I fully understand how these work, but the signature looks different to me than what results from the source code: https://github.com/reactjs/redux/blob/master/src/createStore.js#L49
Should be something like:
In this case
StoreEnhancer
should be generic. This leads to another problem. If it's typed as a generic interface, thenStoreCreator
should be generic as well, in which case we can no longer type thecreateStore
variable. The only way I see to fix this would be to create to interfaces that are basically copy-pastes of each other: