Skip to content

Improve TypeScript types #3566

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
wants to merge 3 commits into from
Closed

Conversation

jednano
Copy link

@jednano jednano commented Sep 7, 2019

The TS enhancement stage got the green light 🚦, so this is a PR towards that effort. Could be some more after this.

@netlify
Copy link

netlify bot commented Sep 7, 2019

Deploy preview for redux-docs ready!

Built with commit ebe7423

https://deploy-preview-3566--redux-docs.netlify.com

@markerikson
Copy link
Contributor

Can you clarify and document what all is being changed?

Copy link
Author

@jednano jednano left a comment

Choose a reason for hiding this comment

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

Here's what's changed in this PR.

): StoreEnhancer<any> {
return (createStore: StoreCreator) => <S, A extends AnyAction>(
reducer: Reducer<S, A>,
export default function applyMiddleware<
Copy link
Author

Choose a reason for hiding this comment

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

The previous implementation only supported a max of 5 middlewares before types started being swallowed. This change fixes that, but introduces a breaking change for TypeScript users who were passing in up to 5 middleware types plus a state S type. Now, the state type is the first generic type. You can provide a state type manually, but the middlewares type will be automatically applied, whether you provide a state type or not.

Copy link
Author

Choose a reason for hiding this comment

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

@timdorr now that I look at this again, I don't think we should merge this, because it requires each middleware to be of the same type. As we discussed at length in other threads, there seems to be no way around this Ext1, Ext2, ... business.

Copy link
Author

Choose a reason for hiding this comment

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

Restored in ebe7423

M extends Middleware<any, any, infer D> ? { dispatch: D } : never,
S
> {
return (createStore: StoreEnhancerStoreCreator<any>) => (
Copy link
Author

Choose a reason for hiding this comment

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

This StoreEnhancerStoreCreator type is new and more accurate than just a plain StoreCreator.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not groking why the StoreEnhancer's Extension here would be an any. We know what apply middleware does (it has a very specific API) and it doesn't do any actual extension of the store's properties. So, at the very least, shouldn't it be {}?

@@ -273,11 +273,7 @@ export default function createStore<
throw new Error('Expected the nextReducer to be a function.')
}

// TODO: do this more elegantly
Copy link
Author

Choose a reason for hiding this comment

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

The elegance is done by line 100, defining a Reducer<any, any>, so that we can keep overwriting it with new reducers w/o issues. This is fine too, because this particular type isn't being returned. It's only used internal to this function.

import * as reducers from './helpers/reducers'
import { addTodo, addTodoAsync, addTodoIfEmpty } from './helpers/actionCreators'
import { thunk } from './helpers/middleware'

describe('applyMiddleware', () => {
it('warns when dispatching during middleware setup', () => {
function dispatchingMiddleware(store) {
function dispatchingMiddleware(store: Store<any, rootActionTypes>) {
Copy link
Author

Choose a reason for hiding this comment

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

Previously, this store was implicitly an any type, which isn't a helpful TS type and is discouraged. Being more explicit here.

@@ -51,16 +59,11 @@ describe('applyMiddleware', () => {
const spy = jest.fn()
const store = applyMiddleware(test(spy), thunk)(createStore)(reducers.todos)

// the typing for redux-thunk is super complex, so we will use an as unknown hack
Copy link
Author

Choose a reason for hiding this comment

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

Now that the store is properly typed, there's no need to use any "hacks".

export function thunk({ dispatch, getState }: MiddlewareAPI) {
return (next: Dispatch) => <T>(action: ThunkAction) =>
export const thunk: Middleware<
ThunkDispatch<any, {}, rootActionTypes>,
Copy link
Author

Choose a reason for hiding this comment

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

This first generic type isn't even used by Middleware.

export const thunk: Middleware<
ThunkDispatch<any, {}, rootActionTypes>,
any,
ThunkDispatch<any, {}, rootActionTypes>
Copy link
Author

Choose a reason for hiding this comment

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

rootActionTypes here limits dispatching only to these action types.


export function todos(state: Todo[] = [], action: TodoAction) {
export function todos(state: Todo[] = [], action: rootActionTypes) {
Copy link
Author

Choose a reason for hiding this comment

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

Now that the action is properly typed as rootActionTypes, the switch statement will narrow down the types to the appropriate one. This type of stuff is what TypeScript is all about!

@@ -82,6 +82,7 @@
"prettier": "^1.18.2",
"rimraf": "^3.0.0",
"rollup": "^1.20.3",
"redux-thunk": "^2.3.0",
Copy link
Author

Choose a reason for hiding this comment

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

If we're going to be testing thunks, it only makes sense that this dev dependency would aid in that effort.

@timdorr
Copy link
Member

timdorr commented Sep 9, 2019

Do you think we could break this up into smaller PRs? It might be easier to look through that way. Either that or at least multiple commits.

@jednano jednano mentioned this pull request Sep 9, 2019
@jednano
Copy link
Author

jednano commented Sep 10, 2019

Unfortunately, it's harder than it seems to break this one apart, as each piece is quite interconnected. If a 150-line PR is too big, I can close it.

@timdorr
Copy link
Member

timdorr commented Sep 30, 2019

@jedmao Can you give this a poke to fix the prettier error in test/helpers/reducers.ts?

@jednano
Copy link
Author

jednano commented Sep 30, 2019

Done!

@jednano
Copy link
Author

jednano commented Oct 23, 2019

@timdorr any updates?

@ematipico
Copy link

@timdorr @markerikson any change to get an alpha release with these types?

@timdorr
Copy link
Member

timdorr commented Nov 14, 2019

No, I haven't had a chance to really think through them.

@timdorr
Copy link
Member

timdorr commented Jul 14, 2020

Closing this out because we never got good consensus. I would recommend re-opening with a smaller scope of work.

@timdorr timdorr closed this Jul 14, 2020
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants