A demonstration of React with TypeScript using PostCSS, Jest, Enzyme, Webpack, and Babel.
Updated for React 16 and Enzyme 3! 🎉
TypeScript
- Use
allowSyntheticDefaultImports: true
to avoid usingimport * as React from 'react'
. This is because React does not have a default export. If you need to access types, you can use a named import (e.g.,import React, { ComponentType } from 'react'
). - Set
target
andmodule
toesnext
, andjsx
topreserve
and let Babel handle transpilation. Babel allows more fine-grained control by using presets and plugins. - You must have
module
set toesnext
to use dynamic imports (presumably when code-splitting with Webpack). You must also be on TypeScript v2.4 or greater. - Set
moduleResolution
tonode
so TypeScript can find your imported modules. - Use
experimentalDecorators: true
if you're using MobX or Radium (or any decorator-based library). - You cannot use angle brackets to type assert (cast) in
.tsx
files (e.g.,(<string>foo).length
). You must use the newas
syntax (e.g.,(foo as string).length
). TypeScript will interpret<string>
as a React component namedstring
. An example of this isrender(<App />, document.getElementById('root') as Element)
. - To import a file (e.g.,
import logo from ./logo.svg
), you need to add a.d.ts
file withdeclare module '*.svg'
in the same directory as the file(s) you want to import (i.e.,./logo.svg
and./AppLogo.d.ts
). You'll obviously still need to usefile-loader
to handle the file. - If you are using CSS Modules, replace
css-loader
withtypings-for-css-modules-loader
in Webpack to generate typings for CSS Modules variables on the fly.
To print the compiled TypeScript output to stdout, use the --outFile /dev/stdout
option from the
command line. This option only works on Linux/macOS and only works with amd
or system
modules.
For example:
tsc src/main/webapp/components/App.tsx --outFile /dev/stdout --target esnext --module system --jsx preserve --allowSyntheticDefaultImports --experimentalDecorators
Jest
- Requires either a custom preprocessor or
ts-jest
. - When using
ts-jest
andjsx: preserve
, you must setuseBabelrc: true
(and obviously have a.babelrc
with either a preset or plugin to transpile JSX). - When running tests in Webstorm, your Jest configuration must be in JSON format. This only applies to Webstorm's built-in Jest test runner, not when using Webstorm to run NPM scripts. This isn't specific to TypeScript, but worth mentioning because you have to have a custom Jest configuration to work with TypeScript.
Webpack
- You can either use
ts-loader
andbabel-loader
if you want complete control over your TypeScript and Babel settings, or useawesome-typescript-loader
which includes Babel, caching, and splitting type checking and compiling to separate processes. - If you do use
ts-loader
, usefork-ts-checker-webpack-plugin
to split type checking and compilation. See the performance optimizations section for more details. - Note that I was unable to get Hot Module Replacement working with
ts-loader
, but others have. HMR worked out of the box withawesome-typescript-loader
. - In order to omit file extensions when importing files (e.g,
import App from './App'
), you need to add.ts
,.tsx
and.js
, to theresolve.extensions
array. Doing this will override the default.js
and.json
extensions, and you'll definitely need.js
in there to work with any 3rd-party library. This isn't any different than what you normally must do with JSX files.
John Reilly wrote an excellent post about increasing performance in Webpack, with an emphasis on TypeScript projects.
I've found that thread-loader
and cache-loader
actually slow down smaller projects due to the
initial startup overhead and took a couple seconds to refresh the browser in development mode
(compared to near-instant otherwise). Experiment with them when your Webpack builds start taking
minutes and not seconds.
Overall, I found awesome-typescript-loader
with useCache: true
to offer the best performance and
make the most sense for me since I'm using both TypeScript and Babel.