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:
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.
CRA works with TypeScript via Babel 7 with zero-config. To enable TypeScript, users can just rename src/index.js
to src/index.tsx
.
paths.appIndexJs
(i.e. src/index.js
-> src/index
) so it works regardless of .js
or .ts
or .tsx
. .ts
and .tsx
to the extensions in webpack config (resolve, babel loader, file-loader) and Jest configuseTypescript
flag (so that this choice is explicit) and related @babel/preset-typescript
package to babel-preset-react-app
paths.appIndexJs
to determine whether to set the useTypeScript
flag in webpack babel-loader options and jest babel transformationtsconfig.json
and tslint.json
be zero config? (probably not)fork-ts-webpack-plugin
? (my vote is against this)tslint-loader
to Webpack config if in "TS mode"eslint-loader
with Babel 7 TS? (I'm not sure)tslint-config-react-app
package that is congruent with eslint-config-react-app
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:
npm install --save typescript @types/react @types/react-dom
(or yarn add typescript @types/react @types/react-dom
)."type-check": "tsc"
to the scripts section of your package.json
."resolutions"
section to your package.json
to avoid conflicting types of React and ReactDOM in your dependencies:"resolutions": {
"**/@types/react": "16.0.40",
"**/@types/react-dom": "16.0.4"
},
tsconfig.json
in 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.
}
}
src/index.js
to src/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.
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)
Question: can we use eslint-loader with Babel 7 TS? (I'm not sure)
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?
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 running npm run flow init
, but once it's on it just works with the build system IIRC.
tsconfig.json
As an alternative to including a sample tsconfig.json
in the docs, if you add "type-check": "tsc"
to your package.json scripts you can run npm run type-check --init
to generate one. The default output doesn't match what you have here, but you can pass in options to tsc --init
to 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?
Thanks for the reply @jergason. Been a while since React Rally!
ESLint Loader Stuff?
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.
When to typecheck
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
/build
command 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 the noEmit:true
config 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 -w
running).
tsconfig.json
tsc --init
requires 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.
resolutions
I've only ever used this is to fix a TS bug regarding nested @types
dependencies when using yarn--never thought of it as "feature." This bug does not impact npm users so this workaround is not needed.
That's quite a few steps to call this "zero config". People should probably still use --scripts-version=react-scripts-ts
or something similar, let it add the extra config files but then add the regular react-scripts to the package.json
Or would it be possible to put these steps in a script like eject
, maybe even let CRA run it automatically if it finds the useTypescript
flag?
@evertbouw I disagree. Furthermore as described above, this setup is almost identical to the effort / config required to setup Flow + plus changing filename.
I really want this, too. Right now this project seems to default to supporting Facebook libraries like flow
and graphql
over 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 like babel-plugin-macros
, various css-in-js plugins and optimizations. (I think this is likely to continue when people start to include stuff like prepack
into 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).
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?
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).
Babel 7 TypeScript does not allow some features of TypeScript such as constant enum and namespaces.
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.
We have TSLint support coming soon over at https://github.com/strothj/react-app-rewire-typescript-babel-preset/pull/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.
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
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.
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 tsc
under 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 ?
@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.
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 tsc under 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 ?
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.
@ianschmitz To be clear, my only comment applies to the idea that whatever standard
TS that goes into Babel, should not cause Babel to fail during its transformation step. If it is just stripping things back to standard
JS, then it sounds like there shouldn't be any issues. 👍 from me! =)
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-plugin
was lost on the first execution (when in async
mode), because of react-dev-utils
doing an automatic clearConsole
when 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 checked tslint
doesn'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.json
at the root folder is used to decide whether to switch TypeScript support on or off.
@sebinsua could you please share a link to the modified fork?
What concerns do you have about using something like create-react-app-typescript?
@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: https://github.com/wmonk/create-react-app-typescript/issues/333, that's a minor thing (although it's considered major for some). When I'm using create-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 ?
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.
@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!
I made the PR #4837 with TypeScript support using babel 7.
Pretty similar to what was proposed here.
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
Can I use typescript without ejecting? It's not clear to me how CRA2 handles .babelrc
for "@babel/typescript"
preset.
@wiesson please see PR #4837 for more info of what is coming!
TypeScript is now officially supported as of Create React App 2.1. Read the release notes to get started!
For those coming from create-react-app-typescript, I've written a short guide on migrating to Create React App.
@jaredpalmer I tried to monkeypatch the fork-ts-checker-webpack-plugin
instance in webpack.config.dev
––in the updated config, I assigned the tslint.json
path to the options.tslint
field (as specified in the docs)... I tried swapping the plugin with an entirely new instance as well. I toggled silent
back 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 of create-react-app
's governance, how would you go about enabling custom TSLint configs?
Most helpful comment
I made the PR #4837 with TypeScript support using babel 7.
Pretty similar to what was proposed here.