-
Notifications
You must be signed in to change notification settings - Fork 282
feat: add typescript support #758
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
Conversation
| @@ -0,0 +1 @@ | |||
| declare module "@reactioncommerce/components/ShopLogo/v1"; | |||
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.
Do we need this?
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.
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.
Ok yes I was also expecting this to become a larger list at some point and therefore wondered if we couldn't avoid that somehow. But IMHO not a blocker, something that could easily be refactored later on.
| viewer: any; | ||
| } | ||
|
|
||
| const Header: FC<HeaderProps> = ({ classes, shop, uiStore }) => { |
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'd like to discuss the general style we adopt here:
Typescript could infer these, should we utilize that and reduce boilerplate, or do we want to be explicit all the time?
Also, FC seems to add no value so we could use const Header = ({ classes, shop, uiStore }: HeaderProps) which I would prefer personally.
I don't want to pick on this specific one as it's just an implementation example, but it's style will potentially be adopted in other places aswell.
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.
My thinking behind use of Type Parameters is to identify type immediately when looking at a function without having parse my eye parse over an argument and possible default params before getting to it, e.g.
const Header = ({
classes: { toolbar, title, controls, appBar },
shop: { name = "cmVhY3Rpb24vc2hvcDo5TVNZOEZ4ZFI2dTJaOHVNdg==" },
uiStore,
}: HeaderProps) => {Add an explicit return type, assign default args or define the types inline and it personally starts to give me the bug eyes even after Prettier has gone to work on it, and still suffers from the eye scanning problem I mentioned:
const Header = ({
classes: { toolbar, title, controls, appBar },
shop: { name = "cmVhY3Rpb24vc2hvcDo5TVNZOEZ4ZFI2dTJaOHVNdg==" },
uiStore,
}: {
shop: {
name: string;
};
uiStore: {
toggleMenuDrawerOpen: Function;
};
viewer: any;
}) => {Then there's the moment where you want to return null inside an element—likely with a ternary expression—and are required to add children to the type definition and you'll still get an error until you choose the correct return type (which FC already does for us).
Type 'Element | null' is not assignable to type 'HeaderProps'.
Type 'null' is not assignable to type 'HeaderProps'.ts(2322)
The biggest disadvantage I see of using FC has to do with potentially adding children where we're not dealing with a react component, in which case I prefer the grammar you supplied.
That said it seems as though others prefer omitting FC to save a little boilerplate and I'm cool with that so long as we can agree on a way forward to get the migration started and let the style grow out of the refactored code before adding any opinion.
Thoughts?
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.
For the record, here's the number of times we're returning null in component definitions which can be used as a rough proxy for how often the above error will occur as people are coding: https://github.com/reactioncommerce/example-storefront/search?q=%22return+null%22&type=code
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.
Thanks for taking the time to explain your thoughts on this!
I'm happy to keep it this way.
Longer-term if we deal with passing more data types from the api (which hopefully we won't all type by hand within components anyway and just use codegen) we can still the what patterns fits best, so I'm negating my original statement, not a blocker and nothing that needs to be set in stone right now.
|
Thanks for getting this started @balibebas! |
|
@janus-reith Just saw your code review. I'll loop back to this soon. |
ghost
left a comment
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.
@janus-reith all set. once you've considered my responses I'm comfortable moving forward with either grammar for the function signatures so we can get this code merged.
|
Let me know if this looks good, and I can get it merged. |
package.json
Outdated
| "rules": { | ||
| "comma-dangle": "off", | ||
| "react/prop-types": "off", | ||
| "quote-props": "off" |
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.
Two more eslint rules worth disabling now as prettier takes care of it:
"react/jsx-max-props-per-line": "off",
"max-len": "off"I'll plan to add these as I incorporate review feedback. 🙏🏼
tsconfig.json
Outdated
| @@ -0,0 +1,21 @@ | |||
| { | |||
| "compilerOptions": { | |||
| "target": "es5", | |||
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.
Should we use "es5" here?
The next's typescript example uses target es next: https://github.com/vercel/next.js/blob/canary/examples/with-typescript/tsconfig.json
and next's itself uses ES2017: https://github.com/vercel/next.js/blob/canary/packages/next/tsconfig.json
TBH I'm unsure what the actual effect of different values here is, since by my understanding, nextjs would not really compile typescript, but typecheck on build and then leverage babel and @babel/preset-typescript to just strip out type definitions.
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.
Seems reasonable to shift forward. I suspect it'll reduce bundle sizes by removing boilerplate for things like generator functions where async could be used.
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.
Looks good to me, thanks @balibebas!
I'd like to reconsider what target we set in tsconfig, but approving for now since my by understanding, impact of that property is rather low for us anyways.
Next step might be introducing https://github.com/dotansimha/graphql-code-generator to derive most types from our api schema. By leveraging the typescript-react-apollo plugin and defining some operations (out of the gql files we have already) we can even auto-generate typed apollo hooks for Querys and Mutations and save us a lot of work.
Signed-off-by: Josh Habdas <jhabdas@protonmail.com>
|
@Akarshit we're all set once ci checks have passed. thanks @janus-reith for your feedback and review |
|
LGTM! If @janus-reith and @Akarshit are good with this let merge |
|
I will give this one a last look tomorrow and then merge it. |
|
I didn't get much time these days, but I will definitely get this done tomorrow. |
|
Backing down a change made during review to prevent non-blocking test warning given the TypeScript target Prevents warning on Jest test runs: See Node target mappings here: https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping |
|
@balibebas Hey! looks like to forgot to do the sign-off for the last commit... |
Signed-off-by: Josh Habdas <jhabdas@protonmail.com>
Nice catch. Done |
|
@balibebas Hey! Sorry it was the weekend so I couldn't get to this one. Looks really good to me. Thanks a lot 🎉 |
|
🎉 This PR is included in version 4.1.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |

Resolves #709
Impact: major
Type: feature
Issue
DX Suffers without TypeScript
Solution
Add strict TypeScript support
Breaking changes
None, though I've changed the code style a little to use functional components, added Prettier to the mix and disabled some ESLint rules in TypeScript files. If we're going to discuss code style now would be a good time. Setting some established patterns now will help others who plan to perform a TypeScript conversion as they fork their Storefronts.
Configuration
Configure VSCode to use Prettier for TypeScript files by opening the Command Palette (Cmd+Shift+P), opening the Settings JSON file and adding:
Then run
ext install esbenp.prettier-vscodeto install it.Testing
yarnto install dependenciesyarn type-checkfrom the command lineHeader.tsxTODOitem forLinkcomponentimportstatement is added automatically/cc @janus-reith @nnnnat