Hello Create React App (CRA) - TypeScript
Taking CRA TypeScript support out for a spin.

As of the October 2018, 2.1.0 release, CRA introduced TypeScript support. While I have always managed a custom-built build solution (i.e., webpack configuration), I have, more recently, been exploring using CRA and thought to give its TypeScript support for a spin.
note: This article is not about customizing the CRA build itself, i.e., ejecting, monkey-patching with customize-cra, or forking react-script.
If you wish to follow along, you will need to have a relatively recent version of Node.js installed; this article was written with 10.14.0.
The final solution from this article is available for download.
Just the Basics
We first scaffold the project:
npx create-react-app hello-cra-ts --typescript
Polyfills
We now add in the standard CRA solution for polyfills; specifically for support in IE 11.
yarn add react-app-polyfill
and update src / index.tsx:
import 'react-app-polyfill/ie11';
...
Linting
The first observation is that unlike JavaScript, TypeScript itself does a considerable amount of code-quality checks before a linter is even introduced.
Because CRA does not expose its linting configurations, we will want to setup linting configurations for the project to enable linting our editor.
note: This assumes that one is using an editor that supports linting, e.g., VS Code with the TSLint, and Prettier — Code Formatter extensions; highly recommended.
Linting — TypeScript
It is unclear if CRA provides any TypeScript linting; it appears to only rely on TypeScript compiler errors. We will go ahead and install the recommended TSLint configuration with Prettier.
We first install the dependencies:
yarn add --dev tslint
yarn add --dev prettier
yarn add --dev tslint-config-prettier
yarn add --dev tslint-plugin-prettier
yarn add --dev tslint-react
We create the Prettier configuration; .prettierrc
We then create the TSLint configuration file; tslint.json:
Finally, we create a lint-ts script in package.json:
{
...
"scripts": {
...
"lint-ts": "tslint -c tslint.json 'src/**/*.{ts,tsx}'",
...
},
...
}
With this script in place, we can lint out project with:
yarn lint-ts
With this in place, we know that it is working as we find a number of errors (and correct them):
- src/serviceWorker.ts: Just put a TSLint ignore at top
- src/index.tsx: As need polyfill at top, disabled first error about import ordering; reordered the other imports
- src/App.tsx: Updated order of imports and added public to render method
Husky and lint-staged
In order to lint before committing and pushing changes, we add Husky and lint-staged.
yarn add --dev husky
yarn add --dev lint-staged
and update package.json:
...
"husky": {
"hooks": {
"pre-commit": "export CI=true && yarn build && lint-staged && yarn test",
"pre-push": "export CI=true && yarn build && lint-staged && yarn test"
}
},
"lint-staged": {
"*.{ts,tsx}": ["tslint -c tslint.json"]
}
...
Wrap Up
We can see that CRA with TypeScript support (with an extra bit of project configuration) gives use a pretty solid build solution. Some of the things that it handles in TypeScript seamlessly under the hood are:
- Media
- Styling, including SASS support (you have to add peer dependency) and CSS Modules
- Tree Shaking / Source Maps / Minification / Caching
- Code Splitting
- Environment Variables
Linting — JavaScript (Optional)
While Create React App supports both TypeScript and JavaScript in the same project, I have lately only been writing TypeScript; thus making this section optional (and not included in the final example).
note: This assumes that one is using an editor that supports linting, e.g., VS Code with the ESLint extension; highly recommended.
For JavaScript, we observe that the built-in linting configuration is lax and that we likely want to use the more strict eslint-config-airbnb (syntax) and Prettier (formatting) configuration.
We first install the dependencies (yes, there are a few):
yarn add --dev eslint
yarn add --dev babel-eslint
yarn add --dev eslint-plugin-import
yarn add --dev eslint-plugin-jsx-a11y
yarn add --dev eslint-plugin-react
yarn add --dev eslint-config-airbnb
yarn add --dev eslint-plugin-prettier
yarn add --dev eslint-config-prettier
yarn add --dev eslint-plugin-jest
note: We presumably already installed Prettier and its configuration file.
We then create the ESLint configuration file; .eslintrc:
Next we add a file to allow our linting configuration to coexist with CRA; .env
Finally, we create a lint-js script and update lint-staged in package.json:
{
...
"scripts": {
...
"lint-js": "eslint 'src/**/*.{js,jsx}'",
...
},
...
"lint-staged": {
...
"*.{js,jsx}": ["eslint"]
}
}
With this script in place, we can lint out project (likely used with a continuous integration solution) with:
yarn lint-js