-
-
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
[DRAFT]: Docs for usage with typescript #3201
Conversation
I'll try to take a look at this in the next few days - been busy with ReactConf and work. |
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.
I find the use of I
in interface names...... icky. It smells of C++ and C# interfaces which are completely different from structural interfaces.
Saw @markerikson 's tweet and made a TypeScript + Redux example based our practice. Check it out: https://codesandbox.io/s/62kw7xvnqw (Note: Do download and try it in VSCode. The type inference on CodeSandbox is not working perfectly at the moment.) To List some advantages:
|
Thank you for the feedback so far. Before I work on the necessary changes, some points of discussion: @Kovensky
|
@HershVar It seems like all the pages in the docs stay away from this particular convention so I wouldn't introduce that in docs about typescript. I also don't think new people will be very familiar with redux at this stage other than have read the previous pages. If you are integrating redux straight into a typescript environment, you would have to have read these docs in order to get started. |
@CarloPalinckx |
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.
Added feedback as per https://www.reddit.com/r/reactjs/comments/9vnaae/typescript_with_react/e9ef7ox/
@danpantry |
Have you considered adding an "advanced" section where you go over things like inference? It currently feels a bit weird you are only using the return type of the root reducer and not the return types for action creators and chat/system reducers. You could stay away from inference at all in the "regular" part and then go all in on inference in that section. I feel like the "Note that you can use inference here" could be relevant to more places in the docs, but that would get pretty messy imo. |
@CarloPalinckx This is also my point from beginning. You can check out my proposed solution, which utilises type inference as much as possible. |
@CarloPalinckx Regarding the addition of "usage with redux thunk" there is one thing I am trying to figure out right now. A thunk returns a function but calling the thunk via props in a component will either return nothing or some other value that is explicitly returned. If anyone has any recommendation on how to add type checking here I would love to hear suggestions. I think the goal here is to have type checking around the parameters and what calling that thunk will return. |
So where do we think this PR stands now? |
I think there are 2 points of discussion to resolve before considering this "ready".
|
Hmm. How difficult would it be to show kind of "side-by-side" examples of both approaches? What are the tradeoffs of each? |
I think doing that may add some unnecessary noise to this page. Going down that path feels like we are teaching more about typescript instead of focusing on the main goal which is to teach how to use redux with typescript. |
@HershVar RE: enums vs string literals People use both. The unique thing about enums here is that the values exist at both run-time and compile-time, but you can accomplish exactly the same thing with constant string literals. It just requires a little more boilerplate.
is almost the same thing as
The only difference is that the former's individual types can't be accessed with dot notation, like Personally, I prefer constants, even though they require extra boilerplate. Why? Mostly just because enums really only provide an alternate syntax for an already existing language feature: discriminated unions. |
With regards to:
If that's the case - Just go with string literals. Enums are unique to TypeScript and I have never personally seen them used for this use case nor would I recommend them. Every JavaScript and TypeScript user is going to understand what a string literal is. |
@joshburgess @danpantry Thanks, I'll make the appropriate changes as soon as I get the time this week. My schedule will finally free up starting next week so I plan to finish up this PR very soon. |
Is that possible to use |
@JounQin
Hopefully this answered your question but feel free to clarify. |
Deploy preview for redux-docs ready! Built with commit d930250 |
Very importantly -- this only works if you use I kinda prefer the You can make the type of the consts easier to use by also exporting an associated type ( The thing I think is a problem, though, is that you no longer get an automatic type with all const values. For that, you need something like // you put this in types.ts itself, it's a circular import but it's
// only used for its typeof, not for its value, so it's safe
import * as types from './types'
export type Actions = Extract<typeof types[keyof typeof types], string> The You also also have to make sure none of your exports are actually typed import { Actions } from './types'
export type Actions = Actions The above are all things that just using an |
How important is using export const FOO = ’FOO’ for action types in the first place! They’re only used in reducers and action creators. I find that this pattern used to be needed on normal JS to prevent misspelling the stringly typed action names. But on TS, if your reducers are written with full static types, typoing say ’FOO’ to ’Foo’ will result in an error. So I’ve moved away from declaring const action type symbols in most of my new code. |
You still need this to, ergonomically, ensure the literal string becomes a literal type if you don't have a contextual type. If you write the string inline in an object (say, But true, it is possible to write it without requiring the consts by always using interfaces that provide a literal contextual type. export interface FooAction {
type: 'FOO'
}
export function doFoo(): FooAction {
// has a contextual type from the return annotation
// so 'FOO' will be literally typed
return { type: 'FOO' }
}
export default function(state = {}, action: FooAction) {
switch(action.type) {
case 'FOO':
// perform 'FOO'
break
default:
unreachable(action)
}
return state
}
// trick to get the compiler to check for exhaustiveness in the switch
function unreachable(value: never) {} The downside is when you want to aggregate the |
OK, this has been open way way too long and looks pretty good to me. I'm going to merge it in. It won't get automatically added to the site, since it's just a single new file. But this opens the door for others to provide PRs on this file and critique via changes, instead of comments. Thanks a ton @HershVar for sticking with this! |
I know this PR got merged already, but just saw an interesting-looking post and wanted to use this as a venue to ping people. Does this post offer any additional useful techniques that are worth showing? https://medium.com/@ankeet.maini/type-redux-with-typescript-without-writing-any-types-5f96cbfef806 |
Status
[January 9, 2019] - Fourth draft completed
[November 12, 2018] - Third draft completed, next revision will include usage with React-Redux & Thunks
[November 10, 2018] - Second draft completed, looking for feedback
[October 29, 2018] - Initial draft ready, looking for feedback
Description
From #2955 , this adds documentation around using redux with typescript.
Notes & Considerations
Misc.
I placed the new doc under the "Advanced" section. If there is a more appropriate place for this specific doc I'd be happy to move it as needed.
I haven't linked this doc to the table of contents (README). If I should do that please let me know.