Using TypeScript with React

February 13, 2019 0 Comments

Using TypeScript with React



TypeScript is awesome. So is React. Let’s use them both together! Using TypeScript allows us to get the benefits of IntelliSense, as well as the ability to further reason about our code. As well as this, adopting TypeScript is easy as files can be incrementally upgraded without causing issues throughout the rest of your project.

Let’s start off by creating a new React project and integrate TypeScript. Run the following commands to initiate the project:

# Make a new directory 
$ mkdir react-typescript # Change to this directory within the terminal
$ cd react-typescript # Initialise a new npm project with defaults
$ npm init -y # Install React dependencies
$ npm install react react-dom # Make index.html and App.tsx in src folder
$ mkdir src
$ cd src
$ touch index.html
$ touch App.tsx # Open the directory in your favorite editor
$ code .

We can then make an index.html file with the following:

<!DOCTYPE html> 
<head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>React + TypeScript</title> <meta name="viewport" content="width=device-width, initial-scale=1">
<body> <div id="main"></div> <script src="./App.tsx"></script>

We’ll be using Parcel as our bundler, but you can elect to use webpack or another bundler if you wish. Or, check this section if you prefer using Create React App. Let’s add Parcel to our project:

# Install Parcel to our DevDependencies 
$ npm i parcel-bundler -D # Install TypeScript
$ npm i typescript -D # Install types for React and ReactDOM
$ npm i -D @types/react @types/react-dom

We can update our package.json with a new task that will start our development server:

{ "name": "react-typescript", "version": "1.0.0", "description": "An example of how to use React and TypeScript with Parcel", "scripts": { "dev": "parcel src/index.html" }, "keywords": [], "author": "Paul Halliday", "license": "MIT" 

We can now populate a Counter.tsx file with a simple counter:

import  as React from 'react'; export default class Counter extends React.Component { state = { count: 0 }; increment = () => { this.setState({ count: (this.state.count += 1) }); }; decrement = () => { this.setState({ count: (this.state.count -= 1) }); }; render () { return ( <div> <h1>{this.state.count}</h1> 
<button onClick={this.increment}>Increment</button>
<button onClick={this.decrement}>Decrement</button>
); }

Then, inside of App.tsx, we can load the Counter:

import  as React from 'react'; 
import { render } from 'react-dom'; import Counter from './Counter'; render(<Counter />, document.getElementById('main'));

Our project can be ran with $ npm run dev and accessed at http://localhost:1234.

Create React App and TypeScript

If you’d rather use Create React App to initiate your project, you’ll be pleased to know that CRA now supports TypeScript out of the box.

Just use the --typescript flag when invoking the create-react-app command:

$ create-react-app my-new-app --typescript 

Functional Components

Stateless or functional components can be defined in TypeScript like so:

import  as React from 'react'; const Count: React.FunctionComponent<{ count: number; 
}> = (props) => { return <h1>{props.count}</h1>;
}; export default Count;

We’re using React.FunctionComponent and defining the object structure of our expected props. In this scenario we’re expecting to be passed in a single prop named count and we’re defining it in-line. We can also define this in other ways, by creating an interface such as Props:

interface Props { count: number; 
} const Count: React.FunctionComponent<Props> = (props) => { return <h1>{props.count}</h1>;

Class Components

Class components can similarly be defined in TypeScript as such:

import  as React from 'react'; import Count from './Count'; interface Props {} interface State { count: number; 
}; export default class Counter extends React.Component<Props, State> { state: State = { count: 0 }; increment = () => { this.setState({ count: (this.state.count += 1) }); }; decrement = () => { this.setState({ count: (this.state.count -= 1) }); }; render () { return ( <div> <Count count={this.state.count} />
<button onClick={this.increment}>Increment</button>
<button onClick={this.decrement}>Decrement</button>
); }

Default Props

We can also define defaultProps in scenarios where we may want to set default props. We can update our Count example to show this:

import * as React from 'react'; interface Props { count?: number; 
} export default class Count extends React.Component<Props> { static defaultProps: Props = { count: 10 }; render () { return <h1>{this.props.count}</h1>;

We’ll need to stop passing this.state.count in to the Counter component too, as this will overwrite our default prop:

render () { return ( <div> <Count /> <button onClick={this.increment}>Increment</button> 
<button onClick={this.decrement}>Decrement</button>

You should now have a project that’s set up to use TypeScript and React, as well as the tools to create your own functional and class-based components!

Tag cloud