React and TypeScript are two superior applied sciences utilized by plenty of builders lately. Realizing the right way to do issues can get tough, and generally it’s onerous to seek out the proper reply. To not fear. We’ve put collectively one of the best practices together with examples to make clear any doubts you’ll have.

Let’s dive in!

How React and TypeScript Work Collectively

Earlier than we start, let’s revisit how React and TypeScript work collectively. React is a “JavaScript library for constructing person interfaces”, whereas TypeScript is a “typed superset of JavaScript that compiles to plain JavaScript.” Through the use of them collectively, we primarily construct our UIs utilizing a typed model of JavaScript.

The explanation you may use them collectively could be to get the advantages of a statically typed language (TypeScript) in your UI. This implies extra security and fewer bugs delivery to the entrance finish.

Does TypeScript Compile My React Code?

A standard query that’s at all times good to evaluation is whether or not TypeScript compiles your React code. The best way TypeScript works is just like this interplay:

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

So the reply is sure, it does! However later, after we cowl the tsconfig.json settings, more often than not you’ll need to use "noEmit": true. What this implies is TypeScript is not going to emit JavaScript out after compilation. It is because sometimes, we’re simply using TypeScript to do our type-checking.

The output is dealt with, in a CRA setting, by react-scripts. We run yarn construct and react-scripts bundles the output for manufacturing.

To recap, TypeScript compiles your React code to type-check your code. It doesn’t emit any JavaScript output (in most eventualities). The output remains to be just like a non-TypeScript React venture.

Can TypeScript Work with React and webpack?

Sure, TypeScript can work with React and webpack. Fortunate for you, the webpack documentation has a guide on that.

Hopefully, that provides you a delicate refresher on how the 2 work collectively. Now, on to finest practices!

Finest Practices

We’ve researched the most typical questions and put collectively this useful record of the most typical use instances for React with TypeScript. This fashion, you should use this text as a reference in your personal initiatives.

Configuration

One of many least enjoyable, but most vital components of growth is configuration. How can we set issues up within the shortest period of time that may present most effectivity and productiveness? We’ll focus on venture setup together with:

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

Undertaking Setup

The quickest solution to begin a React/TypeScript app is through the use of create-react-app with the TypeScript template. You are able to do this by working:

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

It will get you the naked minimal to begin writing React with TypeScript. Just a few noticeable variations 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 varieties of react-scripts, and helps with issues like permitting for SVG imports.

tsconfig.json

Fortunate for us, the most recent React/TypeScript template generates tsconfig.json for us. Nonetheless, they add the naked minimal to get began. We recommend you modify yours to match the one under. We’ve added feedback to elucidate the aim of every possibility as effectively:

{
  "compilerOptions": {
    "goal": "es5", 
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ], 
    "allowJs": true, 
    "skipLibCheck": true, 
    "esModuleInterop": true, "fs") and permits CJS/AMD/UMD fashion imports (import fs from "fs")
    "allowSyntheticDefaultImports": true, 
    "strict": true, 
    "forceConsistentCasingInFileNames": true, 
    "module": "esnext", 
    "moduleResolution": "node", 
    "isolatedModules": true, 
    "resolveJsonModule": true, 
    "noEmit": true, 
    "jsx": "react" 
    "sourceMap": true, 
    "declaration": true, 
    "noUnusedLocals": true, 
    "noUnusedParameters": true, 
    "incremental": true, 
    "noFallthroughCasesInSwitch": true 
  },
  "embrace": [
    "src/**/*" 
  ],
  "exclude": ["node_modules", "build"] 
}

The extra suggestions come from the react-typescript-cheatsheet community and the reasons come from the Compiler Options docs within the Official TypeScript Handbook. It is a fantastic useful resource if you wish to study different choices and what they do.

ESLint/Prettier

So as to be sure that your code follows the principles of the venture or your crew, and the fashion is constant, it’s really useful you arrange ESLint and Prettier. To get them to play properly, comply with these steps to set it up.

  1. Set up the required dev dependencies:

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

    module.exports =  {
      parser:  '@typescript-eslint/parser',  
      extends:  [
        'plugin:react/recommended',  
        'plugin:@typescript-eslint/recommended',  
      ],
      parserOptions:  {
      ecmaVersion:  2018,  
      sourceType:  'module',  
      ecmaFeatures:  {
        jsx:  true,  
      },
      },
      guidelines:  {
        
        
      },
      settings:  {
        react:  {
          model:  'detect',  
        },
      },
    };
    
  3. Add Prettier dependencies:

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

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

    module.exports =  {
      parser:  '@typescript-eslint/parser',  
      extends:  [
        'plugin:react/recommended',  
        'plugin:@typescript-eslint/recommended',  
    +   'prettier/@typescript-eslint',  
    +   'plugin:prettier/recommended',  
      ],
      parserOptions:  {
      ecmaVersion:  2018,  
      sourceType:  'module',  
      ecmaFeatures:  {
        jsx:  true,  
      },
      },
      guidelines:  {
        
        
      },
      settings:  {
        react:  {
          model:  'detect',  
        },
      },
    };
    

These suggestions come from a neighborhood useful resource written referred to as “Using ESLint and Prettier in a TypeScript Project”, by Robert Cooper. In the event you go to this useful resource, you possibly can learn extra in regards to the “why” behind these guidelines and configurations.

VSCode Extensions and Settings

We’ve added ESLint and Prettier and the subsequent step to enhance our DX is to routinely repair/prettify our code on save.

First, set up the ESLint extension and the Prettier extension for VSCode. It will enable ESLint to combine together with your editor seamlessly.

Subsequent, replace your Workspace settings by including the next to your .vscode/settings.json:

{
    "editor.formatOnSave": true
}

It will enable VS Code to work its magic and repair your code while you save. It’s stunning!

These options additionally come from the beforehand linked article “Using ESLint and Prettier in a TypeScript Project”, by Robert Cooper.

Notice: to learn extra about React.FC, look here, and browse here for React.ReactNode.

Parts

One of many core ideas of React is parts. Right here, we’ll be referring to plain parts as of React v16.8, that means ones that use hooks versus courses.

Basically, there’s a lot to be involved with for fundamental parts. Let’s have a look at an instance:

import React from 'react'


operate Heading(): React.ReactNode {
  return <h1>My Web site Heading</h1>
}


const OtherHeading: React.FC = () => <h1>My Web site Heading</h1>

Discover the important thing distinction right here. Within the first instance, we’re writing our operate as a operate declaration. We annotate the return sort with React.Node as a result of that’s what it returns. In distinction, the second instance makes use of a operate expression. As a result of the second occasion returns a operate, as an alternative of a worth or expression, we annotate the operate sort with React.FC for React “Operate Element”.

It may be complicated to recollect the 2. It’s principally a matter of design alternative. Whichever you select to make use of in your venture, use it constantly.

Props

The following core idea we’ll cowl is props. You possibly can outline your props utilizing both an interface or a kind. Let’s have a look at one other instance:

import React from 'react'

interface Props {
  title: string;
  colour: string;
}

sort OtherProps = {
  title: string;
  colour: string;
}


operate Heading({ title, colour }: Props): React.ReactNode {
  return <h1>My Web site Heading</h1>
}


const OtherHeading: React.FC<OtherProps> = ({ title, colour }) =>
  <h1>My Web site Heading</h1>

Relating to varieties or interfaces, we recommend following the rules introduced by the react-typescript-cheatsheet neighborhood:

  • “at all times use interface for public API’s definition when authoring a library or Third-party ambient sort definitions.”
  • “think about using sort in your React Element Props and State, as a result of it’s extra constrained.”

You possibly can learn extra in regards to the dialogue and see a useful desk evaluating varieties vs interfaces here.

Let’s have a look at yet one more instance so we are able to see one thing a bit bit extra sensible:

import React from 'react'

sort Props = {
  
  colour?: string;
  
  kids: React.ReactNode;
  
  onClick: ()  => void;
}

const Button: React.FC<Props> = ({ kids, colour = 'tomato', onClick }) => {
   return <button fashion={{ backgroundColor: colour }} onClick={onClick}>{kids}</button>
}

On this <Button /> part, we use a kind for our props. Every prop has a brief description listed above it to offer extra context to different builders. The ? after the prop named colour signifies that it’s elective. The kids prop takes a React.ReactNode as a result of it accepts all the things that’s a legitimate return worth of a part (read more here). To account for our elective colour prop, we use a default worth when destructuring it. This instance ought to cowl the fundamentals and present you need to write varieties in your props and use each elective and default values.

Basically, maintain this stuff in thoughts when writing your props in a React and TypeScript venture:

  • At all times add descriptive feedback to your props utilizing the TSDoc notation /** remark */.
  • Whether or not you employ varieties or interfaces in your part props, use them constantly.
  • When props are elective, deal with appropriately or use default values.

Hooks

Fortunately, the TypeScript sort inference works effectively when utilizing hooks. This implies you don’t have a lot to fret about. As an illustration, take this instance:



const [value, setValue] = useState('')

TypeScript infers the values given to make use of by the useState hook. That is an space the place React and TypeScript simply work collectively and it’s stunning.

On the uncommon events the place it is advisable initialize a hook with a null-ish worth, you can also make use of a generic and move a union to accurately sort your hook. See this occasion:

sort Consumer = {
  e mail: string;
  id: string;
}




const [user, setUser] = useState<Consumer | null>(null);

The opposite place the place TypeScript shines with Hooks is with userReducer, the place you possibly can benefit from discriminated unions. Right here’s a helpful instance:

sort AppState = {};
sort Motion =
  | { sort: "SET_ONE"; payload: string }
  | { sort: "SET_TWO"; payload: quantity };

export operate reducer(state: AppState, motion: Motion): AppState {
  change (motion.sort) {
    case "SET_ONE":
      return {
        ...state,
        one: motion.payload 
      };
    case "SET_TWO":
      return {
        ...state,
        two: motion.payload 
      };
    default:
      return state;
  }
}

Supply: react-typescript-cheatsheet Hooks section

The sweetness right here lies within the usefulness of discriminated unions. Discover how Motion has a union of two similar-looking objects. The property sort is a string literal. The distinction between this and a kind string is that the worth should match the literal string outlined within the sort. This implies your program is further protected as a result of a developer can solely name an motion that has a sort key set to "SET_ONE" or "SET_TWO".

As you possibly can see, Hooks don’t add a lot complexity to the character of a React and TypeScript venture. If something, they lend themselves effectively to the duo.

Widespread Use Circumstances

This part is to cowl the most typical use instances the place folks stumble when utilizing TypeScript with React. We hope by sharing this, you’ll keep away from the pitfalls and even share this data with others.

Dealing with Kind Occasions

Probably the most frequent instances is accurately typing the onChange used on an enter discipline in a kind. Right here’s an instance:

import React from 'react'

const MyInput = () => {
  const [value, setValue] = React.useState('')

  
  
  operate onChange(e: React.ChangeEvent<HTMLInputElement>) {
    setValue(e.goal.worth)
  }

  return <enter worth={worth} onChange={onChange} id="input-example"/>
}

Extending Element Props

Typically you need to take part props declared for one part and lengthen them to make use of them on one other part. However you may need to modify one or two. Properly, keep in mind how we seemed on the two methods to sort part props, varieties or interfaces? Relying on which you used determines the way you lengthen the part props. Let’s first have a look at the way in which utilizing sort:

import React from 'react';

sort ButtonProps = {
    
    colour: string;
    
    textual content: string;
}

sort ContainerProps = ButtonProps & {
    
    top: quantity;
}

const Container: React.FC<ContainerProps> = ({ colour, top, width, textual content }) => {
  return <div fashion={{ backgroundColor: colour, top: `${top}px` }}>{textual content}</div>
}

In the event you declared your props utilizing an interface, then we are able to use the key phrase extends to primarily “lengthen” that interface however make a modification or two:

import React from 'react';

interface ButtonProps {
    
    colour: string;
    
    textual content: string;
}

interface ContainerProps extends ButtonProps {
    
    top: quantity;
}

const Container: React.FC<ContainerProps> = ({ colour, top, width, textual content }) => {
  return <div fashion={{ backgroundColor: colour, top: `${top}px` }}>{textual content}</div>
}

Each strategies remedy the issue. It’s as much as you to resolve which to make use of. Personally, extending an interface feels extra readable, however in the end, it’s as much as you and your crew.

You possibly can learn extra about each ideas within the TypeScript Handbook:

Third-party Libraries

Whether or not it’s for a GraphQL shopper like Apollo or for testing with one thing like React Testing Library, we regularly discover ourselves utilizing third-party libraries in React and TypeScript initiatives. When this occurs, the very first thing you need to do is see if there’s a @varieties package deal with the TypeScript sort definitions. You are able to do so by working:


yarn add @varieties/<package-name>


npm set up @varieties/<package-name>

As an illustration, for those who’re utilizing Jest, you are able to do this by working:


yarn add @varieties/jest


npm set up @varieties/jest

This might then provide you with added type-safety everytime you’re utilizing Jest in your venture.

The @varieties namespace is reserved for package deal sort definitions. They reside in a repository referred to as DefinitelyTyped, which is partially maintained by the TypeScript crew and partially the neighborhood.

Ought to these be saved as dependencies or devDependencies in my package deal.json?

The quick reply is “it relies upon”. More often than not, they will go underneath devDependencies for those who’re constructing an online utility. Nonetheless, for those who’re writing a React library in TypeScript, you might need to embrace them as dependencies.

There are a number of solutions to this on Stack Overflow, which you will try for additional data.

What occurs in the event that they don’t have a @varieties package deal?

In the event you don’t discover a @varieties package deal on npm, then you definitely primarily have two choices:

  1. Add a fundamental declaration file
  2. Add an intensive declaration file

The primary possibility means you create a file based mostly on the package deal title and put it on the root. If, as an illustration, we wanted varieties for our package deal banana-js, then we might create a fundamental declaration file referred to as banana-js.d.ts on the root:

declare module 'banana-js';

This gained’t present you sort security however it can unblock you.

A extra thorough declaration file could be the place you add varieties for the library/package deal:

declare namespace bananaJs {
    operate getBanana(): string;
    operate addBanana(n: quantity) void;
    operate removeBanana(n: quantity) void;
}

In the event you’ve by no means written a declaration file, then we recommend you check out the guide in the official TypeScript Handbook.

Abstract

Utilizing React and TypeScript collectively in one of the simplest ways takes a little bit of studying as a result of quantity of data, however the advantages repay immensely in the long term. On this article, we lined configuration, parts, props, hooks, frequent use instances, and third-party libraries. Though we might dive deeper into plenty of particular person areas, this could cowl the 80% wanted that can assist you comply with finest practices.

In the event you’d prefer to see this in motion, you possibly can see this example on GitHub.

In the event you’d prefer to get in contact, share suggestions on this text or chat about utilizing the 2 applied sciences collectively, you possibly can attain me on Twitter @jsjoeio.

Additional Studying

In the event you’d prefer to dive deeper, listed here are some sources we recommend:

react-typescript-cheatsheet

Quite a lot of these suggestions got here straight from the react-typescript-cheatsheet. In the event you’re in search of particular examples or particulars on something React-TypeScript, that is the place to go. We welcome contributions as effectively!

Official TypeScript Handbook

One other unbelievable useful resource is the TypeScript Handbook. That is stored updated by the TypeScript crew and supplies examples and an in-depth rationalization behind the internal workings of the language.

TypeScript Playground

Do you know you possibly can take a look at out React with TypeScript code proper within the browser? All you need to do is import React. Right here’s a link to get you started.

Sensible Methods to Advance Your TypeScript Expertise

Learn our information on practical ways to advance your TypeScript skills to set your self up for steady studying as you progress ahead.

LEAVE A REPLY

Please enter your comment!
Please enter your name here