# Using TypeScript In React: Part 1

TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at scale. It has gained wide adoption and I've seen many React developers switch to using TypeScript for their React applications. While there's wide adoption of TypeScript, there are still a lot of teams that don't use TypeScript but are interested in adopting TypeScript for their React projects. There are some concerns or questions that some of these teams or developers ask, such as:

*   How to define types for React components, props and state
    
*   How to use React hooks and event handlers in TypeScript
    
*   Setting up a TypeScript project
    
*   Migrating existing applications to TypeScript
    

I will address some of these questions in this post, and in a follow-up post, I will show you how to migrate a React application to TypeScript.

## Prerequisite

For a better understanding of this post, you should be familiar with React and have basic knowledge of TypeScript. I will show you how to create a new project, define components, and work with hooks and functions in a React application.

Let's get started 🚀

## Setting Up a TypeScript Project

The first question that comes up when I discuss TypeScript with a React dev is `How do I create a React, TypeScript Project?`. You most likely use a tool to create a new React project, for example [Create React App (CRA)](https://create-react-app.dev), which allows you to set up a modern web app by running the command `npx create-react-app react-app`. Frameworks like Next.js, Remix and Gatsby have their own CLI that enables you to set up a TypeScript-base app.

For CRA, you use the command `npx create-react-app react-app --template typescript` to create a TypeScript app. For Next.js it's `npx create-next-app --typescript`. Whichever framework/tool you choose to use, check the documentation for how to use TypeScript.

Using these CLIs, you don't have to configure or specify any TypeScript configuration—they're automatically generated. You can tweak the generated tsconfig.json file to suit your needs. You can add some community recommended config via npm, for example using *@tsconfig/esm*. You can see more info about the different tsconfig extensions at [github.com/tsconfig/bases](http://github.com/tsconfig/bases). I use the Node 16 and Node 17 configuration when building Node.js apps, but using a tool like *create-next-app* I usually don't need additional configuration.

### Using ESLint

You can add TypeScript support to ESLint using the packages `@typescript-eslint/parser` and `@typescript-eslint/eslint-plugin`. The former is used to parse TypeScript code to a format that is understandable by ESLint, while the latter provides TypeScript-specific linting rules. Add them to your project using the command below:

```shell
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
```

Then add the following config to your **.eslintrc.js**

```javascript
module.exports = {
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaVersion: "latest", // Allows the use of modern ECMAScript features
    sourceType: "module", // Allows for the use of imports
  },
  extends: ["plugin:@typescript-eslint/recommended"], // Uses the linting rules from @typescript-eslint/eslint-plugin
  env: {
    node: true, // Enable Node.js global variables
  },
};
```

Check the documentation at [github.com/typescript-eslint/typescript-eslint](http://github.com/typescript-eslint/typescript-eslint) to learn more about TypeScript + ESLint.

## JSX & TypeScript

You can name your files with the **.tsx** extension when working with TypeScript. You don't need to configure anything extra if you used a tool to bootstrap the project. Otherwise, TypeScript has a [*jsx*](https://www.typescriptlang.org/tsconfig#jsx) configuration option that controls how JSX constructs are emitted in JavaScript files. This only affects the output of JS files that end in *.tsx*.

## Function Component

Function components can be written as regular functions that accept arguments and return a React element. For example:

```typescript
export const HelloWorld = () => <h1>Hello World!</h1>;
```

In this example, the return type is inferred by TypeScript. You can choose to specify the return type so that an error is raised if you accidentally return a different type. For example:

```typescript
export const HelloWorld = (): JSX.Element => <h1>Hello World!</h1>;
```

## Typing Props

You can define the type for the function argument either inline or as a separate type declaration.

Here's an example with the prop type defined inline:

```typescript
export const HelloWorld = ({ message }: { message?: string }) => (
  <h1>Hello {message ?? "World"}!</h1>
);
```

You can declare a type using either the `type` alias or as an interface. My personal preference is to use *interface* until I have a need to use the `type` alias. But I've worked with teams that prefer to use the `type` alias in all cases and I go with their approach. You can read more about the differences in the TypeScript [docs](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces), and explore an example in the [TypeScript playground](https://www.typescriptlang.org/play#example/types-vs-interfaces).

### Children Props

If the component accepts other React components as props, you can include the `children` property and set its type to `React.ReactNode`.

```typescript
interface HelloProps {
  message: string;
  children?: React.ReactNode;
}

export const HelloWorld = ({ message, children }: HelloProps) => (
  <>
    <h1>Hello {message ?? "World"}!</h1>
    <div>{children}</div>
  </>
);
```

### What About CSS Styles?

You may ask, "*How would I specify the type of the* `style` attribute of an element?". You can do that using the `React.CSSProperties` type.

Here's an example:

```typescript
interface HelloProps {
  message: string;
  style?: React.CSSProperties;
}

export const HelloWorld = ({ message, style }: HelloProps) => (
  <>
    <h1 style={style}>Hello {message ?? "World"}!</h1>
  </>
);
```

## Hooks

React hooks have been available since version 16.8, and many would encourage you to use functional components with hooks, rather than class components. I will stick to functional components in this post. Check out this [cheatsheet](https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/class_components) if you want to know about using TypeScript with React class components.

### useState

I won't go into details about every React hook available. I'll rather pick a few and show you how to work with hooks. Let's start with the **useState** hook.

You can call useState hook and specify the type for the state as follows:

```typescript
const [message, setState] = useState<string>("hello world");
```

By specifying the type, only string values will be allowed when calling the hook or using the `setState` function. However, type inference works really well in this case. You can rewrite the example above to use inference using the code below:

```typescript
const [message, setState] = useState("hello world");
// inferred type for `message`: string
// setState only accepts string a value
```

Sometimes you want to call *useState* without any argument (or use a null value), and later on update the state with the actual value. In this case, you would need to explicitly specify the type using a union type. For example:

```typescript
const [message, setState] = useState<string | undefined>();
// `message` type: string | undefined
// setState only accepts string a value or undefined
```

When you use type inference and you need the inferred type, you can use the *typeof* operator to get the type. For example:

```typescript
const [state, setState] = React.useState({
  id: 104,
  name: "Joe Lars",
  passportNumber: "A093JK23",
}); // the inferred type is {id: number, name: string, passportNumber: string}

const sendMessage = (user: typeof state) => {
  findPassport(user.passportNumber); // a function using `user`
};
```

### useContext / useMemo / useCallback

Other hooks also have type inference support. Take *useContext* for example, it can infer the type based on the object that is passed in as an argument.

```typescript
type Color = "grey" | "black" | "pink";
const ColorContext = createContext<Color>("pink");

const Header = () => {
  const colour = useContext(ColorContext);
  return <div style={{ colour }}>The legend of Kora</div>;
};
```

*useMemo* and *useCallback* also have their types inferred from the values that they return.

## Events

The types for events are inferred through contextual typing if the event handler is defined inline.

```typescript
<button
  onClick={(e) => {
    // `e` will be correctly typed automatically!
  }}
/>
```

If you define the handler function separately, then you will need to specify the type. The code below is an example of using a text input.

```typescript
const Input = () => {
  const [state, setState] = useState("");

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setState(e.target.value);
  };

  const handlePaste = (e: ClipboardEvent<HTMLInputElement>) => {
    e.preventDefault();
  };

  return (
    <input
      type="text"
      value={state}
      onChange={handleChange}
      onPaste={handlePaste}
    />
  );
};
```

The code snippet has two event handler functions `handleChange` and `handlePaste`. The event object `e` for *handleChange* uses the **ChangeEvent** generic type, while *handlePaste* uses **ClipboardEvent** generic type. Every event has a distinct type. The *cut*, *copy* and *paste* events uses the **ClipboardEvent**. You can look up the list of event types, and more about events in the [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forms_and_events#list-of-event-types).

## Conclusion

In this post, I showed you how to set up a new React project using TypeScript, and how to work with functional components, hooks and event handlers using TypeScript. In the follow-up post, I will walk you through migrating a React project to TypeScript. Stay tuned!

> Originally published on [Telerik Blog](https://www.telerik.com/blogs/using-typescript-react)
