Getting started with React and TypeScript

TypeScript and React are a great match, which already becomes clear during the setup of a project.

The setup isn't as complicated as you may think, as TypeScript already includes all the features needed for compiling React's JSX code to JavaScript. You won't even need Babel anymore when you're finished.

In this article, I'll first explain how to configure TypeScript with the tsconfig file. Afterward, we'll see how to set up an entire project using Webpack or Create React App.

Dependencies

To get started with TypeScript, we need to install the typescript package together with React's type definitions.

yarn add typescript @types/react @types/react-dom

Packages with the @types prefix provide the type definitions for our dependencies.

Many npm packages already include the type definitions out of the box. If they are missing, we'll see compilation errors, in which case we can usually install the matching types:

yarn install -D @types/module-name

React tsconfig.json setup

The tsconfig.json file is the place where we make TypeScript work together with React.

In this section, I'll explain the most important settings.

JSX

JSX is a syntax that combines JavaScript with a templating language that looks similar to HTML. If you were using React before, you're already familiar with it.

A <div /> in JSX compiles to the following JavaScript code:

React.createElement('div')

In React, we use Babel for compiling JSX to JavaScript syntax, but TypeScript is also capable of doing this if we set the jsx field to react.

{
  "compilerOptions": {
    "jsx": "react",
    ...
  }
}

Set this field to react-native if you're using React Native.

We might also set this field to preserve, which won't compile the JSX syntax when we want to use Babel for compiling JSX.

lib

With the lib field, we specify the libraries we want to include in the build.

{
  "compilerOptions": {
    "lib": ["es6", "dom"],
    ...
  }
}

ES6 gives us modern JavaScript features, while DOM adds typings for browser-specific things like HTML, Events, and more.

target

If we want to have better compatibility with older browsers, we can use target to specify the ECMA Script version we want to support.

{
  "compilerOptions": {
    "target": "ES6",
    ...
  }
}

I usually set this to ES6, as this already supports more than 97% of all internet users, which is more than enough for most people.

Synthetic imports

By default, imports in TypeScript have the following syntax:

import * as React from 'React';

If we want to keep importing our modules as we did with Babel, we need to change some settings in our tsconfig file.

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    ...
  }
}

After this, we can deconstruct our imports again and avoid the obligatory asterisk *.

import React, { FC } from 'react';

Strict checks

We can make our TypeScript configuration as strict or relaxed as we want.

Even when just getting started, I recommend you turn on the noImplicitAny setting, which will make the compiler throw an error when we forget to specify a variable's type.

If you want to avoid TypeScript to compile code with errors, you can also enable the noEmitOnError option.

{
  "compilerOptions": {
    "noImplicitAny": true,
    "noEmitOnError": true,
    ...
  }
}

The noImplicitAny option will make the following code throw a compilation error.

const logValue = (value) => console.log(value);

The value has the implicit type any.

const logValue = (value: string) => console.log(value);

Adding a type fixes the error.

I like this option because it makes sure I don't forget to add types. If needed, I can explicitly add any to bypass this rule (not recommended).

Other rules that increase TypeScript's strictness are noImplicitReturns, noImplicitThis, and strictNullChecks.

React tsconfig.json example

Putting everything together, we end up with a file that looks like the following.

{
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src",
    "sourceMap": true,
    "noImplicitAny": true,
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "moduleResolution": "node",
    "module": "commonJS",
    "lib": ["es6", "dom"],
    "target": "ES5",
    "jsx": "react"
  },
  "exclude": [
    "node_modules",
    "dist"
  ]
}

I explained the most important ones you need to get started.

Next, we'll see how to set up TypeScript with Create React App and Webpack.

TypeScript with CRA (Create React App)

The easiest way to start a new React project with TypeScript is by using Create React App.

Using the official TypeScript template, you'll get a fully configured project to get started.

npx create-react-app my-new-ts-project --template typescript

If you have create-react-app installed globally, you can omit npx at the beginning.

Adding TypeScript to an existing CRA project

The setup for already existing CRA apps is as easy as it gets.

All you need to do is to install the following packages, and you're good to go. You don't even need to create a tsconfig file!

yarn add typescript @types/node @types/react @types/react-dom @types/jest

The next step is to rename any file to have the TypeScript extension (.ts or .tsx) and restart your development server.

You can then gradually move your components to TypeScript.

Adding a tsconfig.json file to the root of your project will override the default settings.

TypeScript with Webpack

The first step is to install ts-loader and typescript (if you haven't already).

yarn add typescript ts-loader

With these packages installed, we now modify our webpack.config.js file to use TypeScript.

module.exports = {
  entry: './src/index.ts',  module: {
    rules: [
      {        test: /\.tsx?$/,        use: 'ts-loader',        exclude: /node_modules/,      },    ],
  },
  resolve: {
    extensions: [ '.tsx', '.ts', '.js' ],  },
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

We're now using ts-loader to compile all our source files.

Add TypeScript to an existing webpack project

If you have an already existing project that you want to migrate, you can do so in small steps, using babel-loader for your JavaScript files and ts-loader for TypeScript.

...
{
  test: /\.jsx?$/,
  exclude: /node_modules/,
  loader: 'babel-loader',
},
{
  test: /\.tsx?$/,
  include: path.resolve(__dirname, '../src'),
  exclude: /node_modules/,
  use: 'ts-loader',
},
...

Afterward, you can migrate your project step by step. You can find more information on how to do this in the TypeScript documentation.

Conclusion

That's it! You should now be able to use TypeScript in your React applications. The initial set up can be a bit of effort, but you're now able to enjoy the benefits of a typed language.

In my next article, I'll explain how you can create React components with TypeScript. Make sure to check it out, and if you liked this one, consider subscribing to my email list below.

Previous

How TypeScript helps you build better React apps

05.02.21 | 5 min
In which situations should you give React with TypeScript a try, and when is it better to stick to JavaScript? Speaking of my own experience, I walk you through the pros and cons of a TypeScript based frontend.

Next

How to create React components with TypeScript

18.01.21 | 3 min