Thursday , February 20th 2020

React with TypeScript: Best Practices

React with TypeScript: Best Practices

React and TypeScript are two awesome technologies used by a lot of developers these days. Knowing how to do things can get tricky, and sometimes it’s hard to find the right answer. Not to worry. We’ve put together the best practices along with examples to clarify any doubts you may have.

Let’s dive in!

How React and TypeScript Work Together

Before we begin, let’s revisit how React and TypeScript work together. React is a “JavaScript library for building user interfaces”, while TypeScript is a “typed superset of JavaScript that compiles to plain JavaScript.” By using them together, we essentially build our UIs using a typed version of JavaScript.

The reason you might use them together would be to get the benefits of a statically typed language (TypeScript) for your UI. This means more safety and fewer bugs shipping to the front end.

Does TypeScript Compile My React Code?

A common question that’s always good to review is whether TypeScript compiles your React code. The way TypeScript works is similar to this interaction:

TS: “Hey, is this all your UI code?”
React: “Yup!”
TS: “Cool! I’m going to compile it and make sure you didn’t miss anything.”
React: “Sounds good to me!”

So the answer is yes, it does! But later, when we cover the tsconfig.json settings, most of the time you’ll want to use "noEmit": true. What this means is TypeScript will not emit JavaScript out after compilation. This is because typically, we’re just utilizing TS to do our TypeScript.

The output is handled, in a CRA setting, by react-scripts. We run yarn build and react-scripts bundles the output for production.

To recap, TypeScript compiles your React code to type-check your code. It doesn’t emit any JavaScript output (in most scenarios). The output is still similar to a non-TypeScript React project.

Can TypeScript Work with React and webpack?

Yes, TypeScript can work with React and webpack. Lucky for you, the official TypeScript Handbook has a guide on that.

Hopefully, that gives you a gentle refresher on how the two work together. Now, on to best practices!

Best Practices

We’ve researched the most common questions and put together this handy list of the most common use cases for React with TypeScript. This way, you can follow best practices in your projects by using this article as a reference.

Configuration

One of the least fun, yet most important parts of development is configuration. How can we set things up in the shortest amount of time that will provide maximum efficiency and productivity? We’ll discuss project setup including:

  • tsconfig.json
  • ESLint
  • Prettier
  • VS Code extensions and settings.

Project Setup

The quickest way to start a React/TypeScript app is by using create-react-app with the TypeScript template. You can do this by running:

npx create-react-app my-app --template typescript

This will get you the bare minimum to start writing React with TypeScript. A few noticeable differences are:

  • the .tsx file extension
  • the tsconfig.json
  • the react-app-env.d.ts

The tsx is for “TypeScript JSX”. The tsconfig.json is the TypeScript configuration file, which has some defaults set. The react-app-env.d.ts references the types of react-scripts, and helps with things like allowing for SVG imports.

tsconfig.json

Lucky for us, the latest React/TypeScript template generates tsconfig.json for us. However, they add the bare minimum to get started. We suggest you modify yours to match the one below. We’ve added comments to explain the purpose of each option as well:

{
  "compilerOptions": {
    "target": "es5", // Specify ECMAScript target version
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ], // List of library files to be included in the compilation
    "allowJs": true, // Allow JavaScript files to be compiled
    "skipLibCheck": true, // Skip type checking of all declaration files
    "esModuleInterop": true, // Disbles namespace imports (import * as fs from "fs") and enables CJS/AMD/UMD style imports (import fs from "fs")
    "allowSyntheticDefaultImports": true, // Allow default imports from modules with no default export
    "strict": true, // Enable all strict type checking options
    "forceConsistentCasingInFileNames": true, // Disallow inconsistently-cased references to the same file.
    "module": "esnext", // Specify module code generation
    "moduleResolution": "node", // Resolve modules using Node.js style
    "resolveJsonModule": true, // Include modules imported with .json extension
    "isolatedModules": true, // Transpile each file as a separate module
    "noEmit": true, // Do not emit output (meaning do not compile code, only perform type checking)
    "jsx": "react" // Support JSX in .tsx files
    "sourceMap": true, // *** Generate corrresponding .map file ***
    "declaration": true, // *** Generate corresponding .d.ts file ***
    "noUnusedLocals": true, // *** Report errors on unused locals ***
    "noUnusedParameters": true, // *** Report errors on unused parameters ***
    "experimentalDecorators": true // *** Enables experimental support for ES decorators ***
    "incremental": true // *** Enable incremental compilation by reading/writing information from prior compilations to a file on disk ***
        "noFallthroughCasesInSwitch": true // *** Report errors for fallthrough cases in switch statement ***
  },
  "include": [
    "src/**/*" // *** The files TypeScript should type check ***
  ],
  "exclude": ["node_modules", "build"] // *** The files to not type check ***
}

The additional recommendations come from the [react-typescript-cheatsheet community](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet) and the explanations come from the Compiler Options docs in the Official TypeScript Handbook. This is a wonderful resource if you want to learn about other options and what they do.

ESLint/Prettier

In order to ensure that your code follows the rules of the project or your team, and the style is consistent, it’s recommended you set up ESLint and Prettier. To get them to play nicely, follow these steps to set it up.

  1. Install the required dev dependencies:

    yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react --dev
    
  2. Create a .eslintrc.js file at the root and add the following:

    module.exports =  {
      parser:  '@typescript-eslint/parser',  // Specifies the ESLint parser
      extends:  [
        'plugin:react/recommended',  // Uses the recommended rules from @eslint-plugin-react
        'plugin:@typescript-eslint/recommended',  // Uses the recommended rules from @typescript-eslint/eslint-plugin
      ],
      parserOptions:  {
      ecmaVersion:  2018,  // Allows for the parsing of modern ECMAScript features
      sourceType:  'module',  // Allows for the use of imports
      ecmaFeatures:  {
        jsx:  true,  // Allows for the parsing of JSX
      },
      },
      rules:  {
        // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
        // e.g. "@typescript-eslint/explicit-function-return-type": "off",
      },
      settings:  {
        react:  {
          version:  'detect',  // Tells eslint-plugin-react to automatically detect the version of React to use
        },
      },
    };
    
  3. Add Prettier dependencies:

    yarn add prettier eslint-config-prettier eslint-plugin-prettier --dev
    
  4. Create a .prettierrc.js file at the root and add the following:

    module.exports =  {
      semi:  true,
      trailingComma:  'all',
      singleQuote:  true,
      printWidth:  120,
      tabWidth:  4,
    };
    
  5. Update the .eslintrc.js file:

    module.exports =  {
      parser:  '@typescript-eslint/parser',  // Specifies the ESLint parser
      extends:  [
        'plugin:react/recommended',  // Uses the recommended rules from @eslint-plugin-react
        'plugin:@typescript-eslint/recommended',  // Uses the recommended rules from the @typescript-eslint/eslint-plugin
    +   'prettier/@typescript-eslint',  // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
    +   'plugin:prettier/recommended',  // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
      ],
      parserOptions:  {
      ecmaVersion:  2018,  // Allows for the parsing of modern ECMAScript features
      sourceType:  'module',  // Allows for the use of imports
      ecmaFeatures:  {
        jsx:  true,  // Allows for the parsing of JSX
      },
      },
      rules:  {
        // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
        // e.g. "@typescript-eslint/explicit-function-return-type": "off",
      },
      settings:  {
        react:  {
          version:  'detect',  // Tells eslint-plugin-react to automatically detect the version of React to use
        },
      },
    };
    

These recommendations come from a community resource written called “Using ESLint and Prettier in a TypeScript Project” by Robert Cooper. If you visit his blog, you can read more about the “why” behind these rules and configurations.

VSCode Extensions and Settings

We’ve added ESLint and Prettier and the next step to improve our DX is to automatically fix/prettify our code on save.

First, install the ESLint extension for VSCode. This will allow ESLint to integrate with your editor seamlessly.

Next, update your Workspace settings by adding the following to your .vscode/settings.json:

code block

<!– RM: couldn't get this code block to render properly, so used a screen shot instead

{
"eslint.autoFixOnSave": true,
"eslint.validate": [
"javascript",
"javascriptreact",
{ "language": "typescript", "autoFix": true },
{ "language": "typescriptreact", "autoFix": true }
],
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": false
},
"[javascriptreact]": {
"editor.formatOnSave": false
},
"[typescript]": {
"editor.formatOnSave": false
},
"[typescriptreact]": {
"editor.formatOnSave": false
}
}

-->

This will allow VS Code to work its magic and fix your code when you save. It's beautiful!

These suggestions also come from the previously linked article "Using ESLint and Prettier in a TypeScript Project" by Robert Cooper.

The post React with TypeScript: Best Practices appeared first on SitePoint.