How to Use TypeScript in React Applications

JavaScript is a weakly typed programming language. Because of this, it is very forgiving, and programming errors will likely go unnoticed during development. TypeScript, a library for checking JavaScript types, solves this problem by forcing types on values. This article shows you how to create a React project using TypeScript.


Creating a React project with TypeScript

You can use the create-react-app command to create Typescript projects with the –Template Possibility.

Run the following command to create a new React project with TypeScript:

npx create-react-app app-name 

This command creates a new React and TypeScript project from scratch. You can also add TypeScript to an existing React application.

To do this, navigate to the project you want to add TypeScript to and run the following code:

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

Then swap the .js file extension with .tsx for files you want to convert to TypeScript. Once you have done this, you will get the “React refers to a UMD globally, but the current file is a module.” errors. You can solve it by importing React into each typescript file like this:

import React from "react"

For a simpler solution, create a tsconfig.json and set jsx to “react-jsx”.

{
"compilerOptions": {
"jsx": "react-jsx",
"target": "es6",
"module": "esnext",
},
}

All configuration settings can be found in the TypeScript docs.

Creating a React function component in TypeScript

You define a React function component the same way you define a JavaScript function.

Below is an example of a function component called Greetings.

export default function Greetings() {
return (
<div>Hello world</div>
)
}

This component returns a “Hello world” string, and TypeScript infers its return type. However, you can comment the return type:

export default function Greetings(): JSX.Element {
return (
<div>Hello world</div>
)
}

TypeScript throws an error if the Greetings component returns a value that isn’t a JSX.element.

Using React Props with TypeScript

React allows you to create reusable components through props. For example, the Greetings component can be given a name prop so that the return value is adjusted based on that.

Below is the edited component with a name as a prop. Note the inline type declaration.

function Greetings({name}: {name: string}) {
return (
<div>Hello {name}</div>
)
}

If you pass the name “Jane”, the component returns the message “Hello Jane”.

Instead of writing the type declaration inside the function, you can define it externally like this:

type GreetingsProps = {
name: string;
};

Then pass the defined type to the component like this:

function Greetings({name}: GreetingsProps) {
return (
<div>Hello {name}</div>
)
}

Use the interface keyword if you want to export and extend this type:

export interface GreetingsProps {
name: string;
};

Note the syntax difference between type and interface—interface does not have an equals sign.

You can extend an interface with the following code:

import { GreetingsProps } from './Greetings'
interface WelcomeProps extends GreetingsProps {
time: "string"
}

You can then use the extended interface in another component.

function Welcome({name, time}: WelcomeProps) {
return (
<div>
Good {time}, {name}!
</div>
)
}

Use the “?” symbol with your props interface to define optional props. Here is an example of an interface with an optional name prop.

interface GreetingsProps {
name?: string;
};

If you don’t pass a name prop, TypeScript doesn’t throw an error.

Using React State with TypeScript

In plain JavaScript, you define the useState() hook as follows:

const [customerName, setCustomerName] = useState("");

In this example, TypeScript can easily infer the type of firstName as a string because the default value is a string.

However, sometimes you cannot initialize the status to a defined value. In these cases, you must specify a state value type.

Here are some examples of how types are defined in the useState() hook.

const [customerName, setCustomerName] = useState<string>("");
const [age, setAge] = useState<number>(0);
const [isSubscribed, setIsSubscribed] = useState<boolean>(false);

You can also use an interface in the useState() hook. For example, you can rewrite the example above to use an interface shown below.

interface ICustomer {
customerName: string ;
age: number ;
isSubscribed: boolean ;
}

Use the custom interface in the hook like this:

const [customer, setCustomer] =  useState<ICustomer>({
customerName: "Jane",
age: 10,
isSubscribed: false
});

Using events with TypeScript

Events are essential as they allow users to interact with a web page. In TypeScript, you can type either events or the event handlers.

To illustrate, consider the following Login component, which uses the onClick() and onChange() events.

import { useState } from 'react';
export default function Login() {
const [email, setEmail] = useState('');

const handleChange = (event) => {
setEmail(event.target.value);
};

const handleClick = (event) => {
console.log('Submitted!');
};

return (
<div>
<input type="email" value={email} onChange={handleChange} />
<button onClick={() => handleClick}>Submit</button>
</div>
);
}

This is how you would handle events in plain JavaScript. However, TypeScript expects you to define the event parameter type in the event handler functions. Luckily, React offers multiple event types.

For example, use the changeEvent type for the handleChange() event handler.

import { ChangeEvent, useState } from 'react';
const handleChange = (event:ChangeEvent<HTMLInputElement>) => {
setEmail(event.target.value);
};

The changeEvent type is used to change the values ​​of input, select, and textarea elements. It’s a generic type, which means you must pass the DOM element whose value changes. In this example, you passed the input element.

The example above shows how to enter the event. The following code shows how you can enter the event handler instead.

import { ChangeEventHandler, useState } from 'react';

const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {
setEmail(event.target.value);
};

For the handleClick() event, use the MouseEvent().

import { useState, MouseEvent } from 'react';
const handleClick = (event: MouseEvent) => {
console.log('Submitted!');
};

Again, you can attach the type to the event handler itself.

import { useState, MouseEventHandler } from 'react';
const handleClick: MouseEventHandler = (event) => {
console.log('Submitted!');
};

For other event types, see the React TypeScript cheat sheet.

When creating large forms it is better to use a form library like Formik as it is built with TypeScript.

Why should you use TypeScript?

You can instruct a new React project to use TypeScript or convert an existing one. You can also use TypeScript with React functional components, states, and React events.

Entering React components can sometimes feel like writing unnecessary boilerplate code. However, the more you use it, the more you’ll appreciate its ability to catch bugs before you deploy your code.

Leave a Reply

Your email address will not be published. Required fields are marked *