Skip to content
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

Updated the definition of 'Reducer' and 'Dispatch' for TypeScript 2.3+ #2479

Closed
wants to merge 1 commit into from

Conversation

morlay
Copy link

@morlay morlay commented Jun 29, 2017

No description provided.

index.d.ts Outdated
@@ -43,7 +43,7 @@ export interface Action {
*
* @template S State object type.
*/
export type Reducer<S> = <A extends Action>(state: S | undefined, action: A) => S;
export type Reducer<S, A extends Action = Action> = (state: S, action: A) => S;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is S | undefined removed? Every reducer must accept undefined as the first arg to initialize the state.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so.
For each Reducer, they may need to have the same structure of State, includes the initial state.

And we used to define Reducer with defaults like:

const someReducer: Reducer<State> = (state = {} as State  /* this is may not undefined */, action) => state

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redux itself passes undefined to the reducer on Store init. Typings must reflect this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I have reverted this change.

index.d.ts Outdated
@@ -93,8 +93,8 @@ export function combineReducers<S>(reducers: ReducersMapObject<S>): Reducer<S>;
* transform, delay, ignore, or otherwise interpret actions or async actions
* before passing them to the next middleware.
*/
export interface Dispatch<S> {
<A extends Action>(action: A): A;
export interface Dispatch<A extends Action = Action> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is correct. Redux store is able to dispatch any possible action, so we can't constrain it to a specific subtype.

Also, here's the rationale for making state type a type parameter for Dispatch: #1537
However, for the whole year, I've only seen it being used in redux-thunk. Moreover, it would give type-checking benefits only when dispatch is called directly via store.dispatch(...), but if we e.g. use connect from react-redux, we'd still have to declare state type manually.

In light of the above, I tend to agree that we should consider removing the S type parameter from Dispatch.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, redux-thunk and redux-promise have different type for Dispatch.
But I think they should be re-defined in that packages.
Or just use any here :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about declare Dispatch like this:

export interface Dispatch<TInput = Action, TReturn = Action> {
    (input: TInput): TReturn;
}

for redux-thunk user, can use like store.dispatch<() => Action>(() => ({ type: "action" }))
for redux-promise user, can use like store.dispatch<Action, Promise<Action>>(someAction)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The correct typing for redux-promise is something like

type Dispatch = <T>(action: PromiseAction<T>) => Promise<T>;

Unfortunately there's no way to express this via type parameters. Currently we augment Dispatch signature in third-party middleware typings via module augmentation, and it works fine. There's a chance that with TS 2.4 we could extend Dispatch during store enhancement. I'm going to make some experiments when I have time.

@@ -43,7 +43,7 @@ export interface Action {
*
* @template S State object type.
*/
export type Reducer<S> = <A extends Action>(state: S | undefined, action: A) => S;
export type Reducer<S, A extends Action = Action> = (state: S | undefined, action: A) => S;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should conform with #2467

@aikoven
Copy link
Collaborator

aikoven commented Jul 4, 2017

I am sorry for nagging, in my experience, it is very hard to fix typings without introducing a breaking change, so I just want to make sure we come up with the best typings possible for Redux v4. Otherwise, we would have to wait forever for the next major.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants