Repository navigation
RFC: Zero-config TypeScript with Babel 7 #4146
Description
Zero-config TypeScript with Babel 7
As mentioned in several other issues, with the release of Babel 7 and CRA 2, TypeScript support is now possible in a way that does not dramatically change the core of CRA internals. Before proceeding with a PR, would love to gather feedback on a solution / implementation I came up with over the weekend:
Current Behavior
TypeScript users cannot use CRA directly. Popular alternatives include react-scripts-ts (a fork of CRA that uses the TypeScript compiler) and Microsoft's React TypeScript boilerplate.
Desired Behavior
CRA works with TypeScript via Babel 7 with zero-config. To enable TypeScript, users can just rename src/index.js to src/index.tsx.
Suggested Solution
- Remove filename extension from
paths.appIndexJs(i.e.src/index.js->src/index) so it works regardless of.jsor.tsor.tsx. - Add
.tsand.tsxto the extensions in webpack config (resolve, babel loader, file-loader) and Jest config - Add a
useTypescriptflag (so that this choice is explicit) and related@babel/preset-typescriptpackage tobabel-preset-react-app - Use the filename extension of
paths.appIndexJsto determine whether to set theuseTypeScriptflag in webpack babel-loader options and jest babel transformation - Add documentation about TypeScript usage
Areas of Interest/Discussion/Questions
- Alternative ways to determine whether to enable TS?
- Should
tsconfig.jsonandtslint.jsonbe zero config? (probably not) - Should we add built-in type checking with
fork-ts-webpack-plugin? (my vote is against this) - (bonus) Add
tslint-loaderto Webpack config if in "TS mode"- Question: can we use
eslint-loaderwith Babel 7 TS? (I'm not sure) - If not, we should add a minimal
tslint-config-react-apppackage that is congruent witheslint-config-react-app
- Question: can we use
Suggested Documentation
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Check out this introduction to using static types in JavaScript if you are new to this concept.
Recent versions of TypeScript work with Create React App projects out of the box thanks to Babel 7. Babel 7 TypeScript does not allow some features of TypeScript such as constant enum and namespaces. You can read more about Babel TypeScript here.
To add TypeScript to a Create React App project, follow these steps:
- Run
npm install --save typescript @types/react @types/react-dom(oryarn add typescript @types/react @types/react-dom). - Add
"type-check": "tsc"to the scripts section of yourpackage.json. - Add a
"resolutions"section to yourpackage.jsonto avoid conflicting types of React and ReactDOM in your dependencies:
"resolutions": {
"**/@types/react": "16.0.40",
"**/@types/react-dom": "16.0.4"
},- Create a file called
tsconfig.jsonin the root of your project:
{
"compilerOptions": {
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"jsx": "react", /* Use React to interpret JSX */
"noEmit": true, /* Do not emit outputs. */
"allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export.
}
}- Rename
src/index.jstosrc/index.tsx
Now you can run npm run type-check (or yarn type-check) to check the files for type errors. You can optionally use an IDE like Nuclide or VSCode for a better integrated experience.
To learn more about TypeScript, check out its documentation.
Activity
[-][2.0] Zero-config TypeScript with Babel 7[/-][+][RFC]: Zero-config TypeScript with Babel 7[/+][-][RFC]: Zero-config TypeScript with Babel 7[/-][+]RFC: Zero-config TypeScript with Babel 7[/+]jergason commentedon Mar 30, 2018
Thanks for thinking about this! I think it would be fantastic if CRA supported TypeScript. Some initial feedback as someone mucking around with trying to update react-scripts-ts to CRA 2.0.0 (https://github.com/jergason/create-react-app-typescript/tree/jergason/update-to-2.0)
ESLint Loader Stuff?
I might be misunderstanding this. Are you asking if we can lint TypeScript files with eslint-loader?
What eslint parser would this use? I've been using eslint with https://github.com/eslint/typescript-eslint-parser and it has a few major issues. It parses TypeScript successfully, but it falsely flags interfaces and fields in interfaces as undefined variables.
Or are you just saying we'd lint the code after compiling it?
When To Type Check
You're suggesting running the compiler as a separate package.json script, which means the build wouldn't type check, right? This means anyone who wants to make sure their builds type check correctly needs to tweak their package.json more, which seems to go against the "zero config" philosophy. Flow support requires adding a
"flow": "flow"script to your package.json and then runningnpm run flow init, but once it's on it just works with the build system IIRC.Zero-config (or less config)
tsconfig.jsonAs an alternative to including a sample
tsconfig.jsonin the docs, if you add"type-check": "tsc"to your package.json scripts you can runnpm run type-check --initto generate one. The default output doesn't match what you have here, but you can pass in options totsc --initto customize it. Maybe we could just include the options to pass to the command in the readme?Also, for parity with the way flow works, maybe it's better to name this field in package.json
tsc?"resolutions"section in package.jsonI think this feature is yarn-only. Is there a way to make this work for npm users as well?
jaredpalmer commentedon Mar 30, 2018
Thanks for the reply @jergason. Been a while since React Rally!
I'm not up on my eslint stuff cuz I work in TS all day. I'd rather use
tslint, but was just wondering if there was a new eslint thing with Babel 7 TS that could make for less code to manage/PR smaller.Yes. My suggestion is that typechecking would happen in a separate process (and terminal window). I was just going for parity with Flow documentation and method of installation here. AFAIK flow does indeed need to be run in a separate process, but editor plugins pick up flow immediately and the same is true for typescript.
So to summarize:
yarn start/buildcommand in. I use this on my Razzle projects at the moment, and it works very well. However, to get the absolute best performance, it requires tweaking the number of workers it uses. Using too many actual decreases performance and slows down compiles in my experience. This is why I suggest not using it for CRA.tsc -w: Leverage typescript's compiler just for typechecking as descibed (when used with thenoEmit:trueconfig flag. This would need to be run in a separate process and terminal window (like Flow).Note that neither options impact how editor plugins interact with TypeScript. For example, VSCode language server will pick up and display TS and TSLint errors in the background on open files (without
tsc -wrunning).tsc --initrequires typescript to be globally installed. It also outputs a mess of a file IMHO. My suggestion was to just make it as easy as possible to understand what is going on. I'm totally fine adding CLI options to curtail output if that's preferred over copypasta.I've only ever used this is to fix a TS bug regarding nested
@typesdependencies when using yarn--never thought of it as "feature." This bug does not impact npm users so this workaround is not needed.evertbouw commentedon Apr 6, 2018
That's quite a few steps to call this "zero config". People should probably still use
--scripts-version=react-scripts-tsor something similar, let it add the extra config files but then add the regular react-scripts to the package.jsonOr would it be possible to put these steps in a script like
eject, maybe even let CRA run it automatically if it finds theuseTypescriptflag?jaredpalmer commentedon Apr 6, 2018
@evertbouw I disagree. Furthermore as described above, this setup is almost identical to the effort / config required to setup Flow + plus changing filename.
sebinsua commentedon May 8, 2018
I really want this, too. Right now this project seems to default to supporting Facebook libraries like
flowandgraphqlover what is most popular in the wild.Obviously, there is already
react-scripts-ts, but I personally think that TypeScript's tooling is a dead-end. Babel is a better integration point for stuff likebabel-plugin-macros, various css-in-js plugins and optimizations. (I think this is likely to continue when people start to include stuff likeprepackinto their builds, too.)There is already this (
react-app-rewire-typescript-babel-preset) but I don't think it's a good idea to monkey-patch bits of config (as when they change, fixing it will involve modifying a function with some relationship to the config, instead of a more concrete object literal).codepunkt commentedon May 17, 2018
This is such an amazing idea and really well thought-out. Thanks for the work @jaredpalmer and @jergason!
Would love to see this. How can we help?
BernieSumption commentedon May 24, 2018
I'd be happy to help develop and test this if it gets past the proposal stage. I would suggest adopting a "light touch" approach - just do the minimum to enable TS development, and let users configure TSLint if they want to, like the approach taken with Sass.
As for exposing tsconfig.json, I think you can probably hide it. Just enable all the various features like decorators. A good argument for hiding it is that usage with Babel requires
"isolatedModules": true(or rather, if the flag is omitted then people can write code that will not function correctly with Babel).lookfirst commentedon May 28, 2018
While I would love to see CRA support TypeScript out of the box, I personally don't agree with using a version of the typescript compiler that isn't compatible with the actual TypeScript compiler. I think that will cause a lot of confusion and brittleness over time.
ianschmitz commentedon Jun 16, 2018
We have TSLint support coming soon over at strothj/react-app-rewire-typescript-babel-preset#14.
I think this will be a great solution for those wanting TS support in CRA 2.0. Would be great to hear feedback on what the community would like to see regarding TSLint.
It's worth taking a look at the logic needed to wire in TS support.. there really wasn't much needed! My preference would be to have TS supported directly by CRA, but i understand the desire to keep things as simple as possible.
reyronald commentedon Jul 6, 2018
I've been very excitedly following this issue since the day it was opened, and want to thank @jaredpalmer for taking the first step in that direction by crafting this proposal. However, I haven't seen much attention from the maintainers and that makes me sad :(. It's understandable though, I know there are a lot of other priorities, but I think having TS support out of the box would be a HUGE benefit.
Is there anything we can do to push this forward a little? Maybe make a PR with a proof of concept? Since I'm so heavily interested in this I'm willing to contribute in any way possible.
/cc @gaearon
I somewhat agree with @lookfirst 's statement here. I don't know how Babel 7 compiles TS and haven't looked into it, but I'm assuming that it doesn't use
tscunder the hood given that there are some features from the language it doesn't support. Is there no simple way we could achieve it using the official transpiler instead of Babel ?rajington commentedon Jul 6, 2018
@reyronald What unsupported language features are you missing? What concerns do you have about using something like create-react-app-typescript?
It'd be hard to maintain CRA's painless dev experience if every TypeScript feature needs to work perfectly with everything else CRA offers. It'd likely increase the number of issues and integrations CRA has to worry about (importing images, for example).
Maybe we need to see something like CRA from Microsoft, but in the meantime they're highlighting this approach as well.
ianschmitz commentedon Jul 7, 2018
Babel doesn't really compile the TS. It strips the types from the source leaving plain JS, and continues running the result through babel (like
babel-preset-flow). There are some advantages to this such as that we can take full advantage of the babel ecosystem of plugins, like what CRA already has configured.lookfirst commentedon Jul 7, 2018
@ianschmitz To be clear, my only comment applies to the idea that whatever
standardTS that goes into Babel, should not cause Babel to fail during its transformation step. If it is just stripping things back tostandardJS, then it sounds like there shouldn't be any issues. 👍 from me! =)sebinsua commentedon Jul 9, 2018
Within my current workplace we're currently using a forked version of React Scripts which achieves the zero-config TypeScript setup described here. We've not had any serious problems with it so far.
The only problem we've had was that the output of
fork-ts-checker-pluginwas lost on the first execution (when inasyncmode), because ofreact-dev-utilsdoing an automaticclearConsolewhen the compilation is first finished.I think perhaps you wouldn't want to use this plugin in
create-react-app, however if you don't use it then a developer will need to rely on something else to run typechecks and lints in watch mode -- this is sometimes problematic, for example: last I checkedtslintdoesn't have a CLI watch mode.In my fork TypeScript support is always switched on, however it could be changed so that the existence of a
tsconfig.jsonat the root folder is used to decide whether to switch TypeScript support on or off.brunolemos commentedon Jul 29, 2018
@sebinsua could you please share a link to the modified fork?
reyronald commentedon Jul 29, 2018
@rajington Just the fact that it's a separate project not officially maintained by Facebook and that needs a separate effort to keep in sync with
react-scripts's progress. Take a look at this issue as an example: wmonk/create-react-app-typescript#333, that's a minor thing (although it's considered major for some). When I'm usingcreate-react-app-typescript, I'm not 100% confident that the decisions taken in that project would be approved by the original authors of CRA.Are you against of including official TS support in CRA ?
@ianschmitz Thanks! Like I said, I didn't know how it worked. If that's how it is, I'm not very concerned by what I mentioned before. And I definitely prefer to stay in the Babel ecosystem because of what you just mentioned.
In general, I would like to know how the rest of the community feels about having TS support in CRA? I originally thought it was a no-brainer "yes", but seeing some of your concerns and comments it feels like not everybody thinks the same way, but it is not crystal clear to me if you are leaning on "yes" or "no". Especially because there's no PR open to move this forward!
brunolemos commentedon Jul 29, 2018
I made the PR #4837 with TypeScript support using babel 7.
Pretty similar to what was proposed here.
hieu-nv commentedon Oct 4, 2018
I have created a version of react-scripts to use TypeScript with zero configuration. Please try to use https://www.npmjs.com/package/@hieunv/react-scripts
wiesson commentedon Oct 9, 2018
Can I use typescript without ejecting? It's not clear to me how CRA2 handles
.babelrcfor"@babel/typescript"preset.ianschmitz commentedon Oct 9, 2018
@wiesson please see PR #4837 for more info of what is coming!
Timer commentedon Oct 30, 2018
TypeScript is now officially supported as of Create React App 2.1. Read the release notes to get started!
Vinnl commentedon Oct 30, 2018
For those coming from create-react-app-typescript, I've written a short guide on migrating to Create React App.
harrysolovay commentedon Nov 27, 2018
@jaredpalmer I tried to monkeypatch the
fork-ts-checker-webpack-plugininstance inwebpack.config.dev––in the updated config, I assigned thetslint.jsonpath to theoptions.tslintfield (as specified in the docs)... I tried swapping the plugin with an entirely new instance as well. I toggledsilentback and forth... I'm not sure where I'm going wrong or if this is even the right approach. Really hoping you have some insight into how I can solve this problem. If not for the strict standards ofcreate-react-app's governance, how would you go about enabling custom TSLint configs?