Minimal TypeScript Crash Course For React - With Interactive Code Exercises
Tags: react, javascript, webdev, frontend
Published: 2022-11-25 12:32:59

---
description: Learning TypeScript is THE best investment. Here's everything you need to get started. Follow the story of a nasty CTO called Pat to learn the basics of TS and React.
---

Even if you haven’t worked with TypeScript yet, you probably heard about it. It’s seen vast adoption in the React world in the past years. As of today, almost all React jobs seem to require TypeScript knowledge.

So, many React devs ask themselves: Do I really need to learn TypeScript?

I get it, you have lots on your plate already. And especially if you’re still trying to break into the industry you’re likely overwhelmed with all the stuff to learn. But take it from [this dev](https://www.reddit.com/r/reactjs/comments/yh5g01/comment/iucgnce/):

![A developer’s opinion of TypeScript with React](https://media.graphassets.com/3qi4Jf2SJGLR3j20wb5D)

Learning TypeScript is easily the best investment:

- You’re chances to get a job increase.
- Your code will be less buggy and easier to read/maintain.
- Refactoring code and updating dependencies will be much easier.

In short, your developer experience will skyrocket. Still, you’ll likely have a rough time at first. Lots of strange errors and coding that feels like you have one hand tied behind your back (plus 4 of the remaining fingers glued together).

This page aims at getting you up to speed quickly without overwhelming you with all the details. You’ll get a rather minimal introduction to using TypeScript with React. To make the knowledge stick you can **find interactive code exercises after almost every section**.

Since this easily becomes a rather dry topic we loosely follow the anti-hero of this story: Pat, a nasty CTO.

> Note that the code editor used for the exercises on this page is quite new. If you run into problems I’d appreciate a bug report at bugs@profy.dev.

## TypeScript Basics Required For React

### Primitives

Their name is diminishing, but the three primitives are at the core of all types. 

```typescript
string // e.g. "Pat"
boolean // e.g. true
number // e.g. 23 or 1.99
```

### Arrays

Arrays can be built from primitives or any other type.

```typescript
number[] // e.g. [1, 2, 3]
string[] // e.g. ["Lisa", "Pat"]
User[] // custom type e.g. [{ name: "Pat" }, { name: "Lisa" }]
```

### Objects

Objects are everywhere and they can be really powerful. Just as in this example:

```typescript
const user = {
  firstName: "Pat",
  age: 23,
  isNice: false,
  role: "CTO",
	skills: ["CSS", "HTML", "jQuery"]
}
```

What a “CTO”! The TypeScript type describing this object looks like this:

```typescript
type User = {
  firstName: string;
  age: number;
  isNice: boolean;
  role: string,
  skills: string[];
}
```

Obviously, people don’t only consist of primitives.

```typescript
type User = {
  firstName: string;
  ...
	friends: User[];
}
```

But looking at our “CTO”, it’s good that we can make fields optional. Pat clearly chose his career over his friends:

```typescript
const user = {
  firstName: "Pat",
  age: 23,
  isNice: false,
  role: "CTO",
	skills: ["CSS", "HTML", "jQuery"],
	friends: undefined
}
```

As hard as this may be in the life of Pat, in TypeScript it’s as simple as adding a `?`:

```typescript
type User = {
  firstName: string;
  ...
	friends?: User[];
}
```

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/objects-)

### Enums

Remember, we defined the `User.role` field as a `string`. 

```typescript
type User = {
  ...
  role: string,
}
```

Pat as the “CTO” isn’t happy about that. He knows that the `string` type isn’t restrictive enough. His employees shouldn’t be able to select any role they want.

Enums to his rescue!

```typescript
enum UserRole {
  CEO,
  CTO,
  SUBORDINATE,
}
```

This is much better! But Pat isn’t stupid: he knows that the values of this enum internally are only numbers. Even though the CEO is at the top (kiss-ass Pat) its numeric value is `0`. Zero! The CTO is 1. And the subordinate is a 2? 

Seems inappropriate. How come everyone's more valuable than the leadership?

Luckily, we can use string values for our enums instead.

```typescript
enum UserRole {
  CEO = "ceo",
  CTO = "cto",
  SUBORDINATE = "inferior-person",
}
```

This is very helpful when you want to get a message across (looking at you Pat). But it can also be useful when working with strings coming from an API.

Anyway, Pat is pleased now. He can safely assign anyone their appropriate role.

```typescript
enum UserRole {
  CEO = "ceo",
  CTO = "cto",
  SUBORDINATE = "inferior-person",
}

type User = {
  firstName: string;
  age: number;
  isNice: boolean;
  role: UserRole,
  skills: string[];
  friends?: User[];
}

const user = {
  firstName: "Pat",
  age: 23,
  isNice: false,
  role: UserRole.CTO, // equals "cto"
	skills: ["CSS", "HTML", "jQuery"]
}
```

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/enums-)

### Function

What’s likely the favorite activity of any person in power? Not sure, but Pat certainly loves to demonstrate his power by firing a bunch of losers. 

So let’s make Pat happy and write a function that increases his firing performance.

**Typing Function Parameters**

We have three ways to identify the person to be fired. First, we can use multiple parameters.

```typescript
function fireUser(firstName: string, age: number, isNice: boolean) {
  ...
}

// alternatively as an arrow function
const fireUser = (firstName: string, age: number, isNice: boolean) => {
  ...
}
```

Second, by we can wrap all of the above parameters in an object and define the types inline.

```typescript
function fireUser({ firstName, age, isNice }: {
  firstName: string;
  age: number;
  isNice: boolean;
}) {
  ...
}
```

And finally (since the above isn’t very readable) we can also extract the type. Spoiler alert: this is what we see with React component props a lot.

```typescript
type User = {
  firstName: string;
  age: number;
  role: UserRole;
}

function fireUser({ firstName, age, role }: User) {
  ...
}

// alternatively as arrow function
const fireUser = ({ firstName, age, role }: User) => {
  ...
}
```

**Typing Function Return Values**

Simply firing a user might not be enough for Pat. Maybe he wants to insult them even more? So it might be a good idea to return the user from the function.

Again there are multiple ways of defining the return type. First we can add `: MyType` behind the closing bracket of the parameter list.

```typescript
function fireUser(firstName: string, age: number, role: UserRole): User {
  // some logic to fire that loser ...
  return { firstName, age, role };
}

// alternatively as an arrow function
const fireUser = (firstName: string, age: number, role: UserRole): User => {
  ...
}
```

This enforces that the correct type is returned. If we’d try to return something else (e.g. `null`) TypeScript wouldn’t let us.

![TypeScript enforces correct return type](https://media.graphassets.com/PXKg9wntRpO5gUWjcRCE)

If we don’t want to be that strict, we can also let TypeScript infer the return type.

```typescript
function fireUser(user: User) {
  // some logic to fire that loser ...
  return user;
}
```

Here we simply return the input parameters. This could also be the return value of the “firing” logic. But since the type of the returned value `user` is clear TypeScript automatically knows the return type of the function.  

![TypeScript infers return value](https://media.graphassets.com/tqhxExVDT6OSZwEjDV2x)

So with TypeScript less is often better. You don’t need to define types everywhere but can often rely on type inference. When in doubt simply hover with your mouse cursor on top of the variable or function in question as shown in the screenshot above.

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/functions-)

### Things That You’ll Likely Encounter

Here are a few more things that we don’t cover here but you’ll encounter rather sooner than later.

- [Unions (TypeA | TypeB)](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types)
- [Key-value pairs via Record<TypeA, TypeB>](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)

[![React on the job - email course](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/skyncbvxln80rmks31wq.png)](https://profy.dev/around-react-email-workshop)

## React With TypeScript

When it comes to React and TypeScript the basics from above sections are usually sufficient. After all, React function components and hooks are simple functions. And props are just objects. In most cases, you don’t even need to define any types as TypeScript knows how to infer them.

### Functional Components With TypeScript

For the most part, you don’t need to define the return type of your components. You’d definitely type the props (as we’ll see in a bit). But a simple prop-less component doesn’t need any types.

```typescript
function UserProfile() {
  return <div>If you're Pat: YOU'RE AWESOME!!</div>
}
```

The return type is `JSX.Element` as you can see in this screenshot.

![React components return JSX.Element type](https://media.graphassets.com/QyanWmfpSDu7xCTiUr88)

The great thing: If we mess up and return anything from a component that is not valid JSX, TypeScript warns us. 

![TypeScript warns when a component returns invalid JSX](https://media.graphassets.com/lIu2xyGQi2Zx3QhScCoL)

In this case, a `user` object isn’t valid JSX so we get an error: 

```typescript
'UserProfile' cannot be used as a JSX component.
Its return type 'User' is not a valid JSX element.
```

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/components-)

### Props With TypeScript

The `UserProfile` pays our “CTO” Pat a nice compliment. But it shows the same message for every user and that feels like an insult. Obviously, we need props.

```typescript
enum UserRole {
  CEO = "ceo",
  CTO = "cto",
  SUBORDINATE = "inferior-person",
}

type UserProfileProps = {
  firstName: string;
  role: UserRole;
}

function UserProfile({ firstName, role }: UserProfileProps) {
	if (role === UserRole.CTO) {
    return <div>Hey Pat, you're AWESOME!!</div>
  }
  return <div>Hi {firstName}, you suck!</div>
}
```

If you’re more into arrow functions the same component looks like this.

```typescript
const UserProfile = ({ firstName, role }: UserProfileProps) => {
	if (role === UserRole.CTO) {
    return <div>Hey Pat, you're AWESOME!!</div>
  }
  return <div>Hi {firstName}, you suck!</div>
}
```

A final note: In the wild, you find a lot of code that uses `React.FC` or `React.FunctionComponent` to type components. [This is not recommended anymore though.](https://github.com/facebook/create-react-app/pull/8177)

```typescript
// using React.FC is not recommended
const UserProfile: React.FC<UserProfileProps>({ firstName, role }) {
  ...
}
```

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/props-)

### Callback Props

As you know, in React we often pass around callback functions as props. So far we haven’t seen fields of type function. So let me quickly show you:

```typescript
type UserProfileProps = {
  id: string;
  firstName: string;
  role: UserRole;
  fireUser: (id: string) => void;
};

function UserProfile({ id, firstName, role, fireUser }: UserProfileProps) {
  if (role === UserRole.CTO) {
    return <div>Hey Pat, you're AWESOME!!</div>;
  }
  return (
    <>
      <div>Hi {firstName}, you suck!</div>
      <button onClick={() => fireUser(id)}>Fire this loser!</button>
    </>
  );
}
```

Note: `void` is the return type of the function and stands for “nothing”.

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/props-callbacks-)

### Default Props

Remember: we can make a field optional by marking it with `?`. We can do the same with optional props. Here the `role` isn’t required.

```typescript
type UserProfileProps = {
  age: number;
  role?: UserRole;
}
```

If we want to have a default value for an optional prop we can assign it when restructuring the props.

```typescript
function UserProfile({ firstName, role = UserRole.SUBORDINATE }: UserProfileProps) {
  if (role === UserRole.CTO) {
    return <div>Hey Pat, you're AWESOME!!</div>
  }
  return <div>Hi {firstName}, you suck!</div>
}
```

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/default-props-)

### useState Hook With TypeScript (Inferred Type)

The most used hook in React is `useState()`. And in many cases, you don’t need to type it. If you use an initial value TypeScript can infer the type.

```typescript
function UserProfile({ firstName, role }: UserProfileProps) {
  const [isFired, setIsFired] = useState(false);
  return (
    <>
      <div>Hi {firstName}, you suck!</div>
      <button onClick={() => setIsFired(!isFired)}>
        {isFired ? "Oops, hire them back!" : "Fire this loser!"}
      </button>
    </>
  );
}
```

![TypeScript infers type of React state](https://media.graphassets.com/qOLB9sW6RGmjkSNEYO6L)

Now we’re safe. If we try to update the state with anything else than a boolean we get an error.

![TypeScript warns when setting the wrong type as state](https://media.graphassets.com/TfDEZ4auRceo3w2luAko)

[![React on the job - email course](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/skyncbvxln80rmks31wq.png)](https://profy.dev/around-react-email-workshop)

### useState Hook With TypeScript (Manually Typed)

In other cases, TypeScript can’t infer the type properly from the initial value though. For example:

```typescript
// TypeScript doesn't know what type the array elements should have
const [names, setNames] = useState([]);

// The initial value is undefined so TS doesn't know its actual type
const [user, setUser] = useState();

// Same story when we use null as initial value
const user = useState(null);
```

![In some situations TypeScript can’t infer the type of the state](https://media.graphassets.com/kmwI5JpCS3WtxOAAAQIe)

`useState()` is implemented with a so-called generic type. We can use this to type our state properly:

```typescript
// the type of names is string[]
const [names, setNames] = useState<string[]>([]);
setNames(["Pat", "Lisa"]);

// the type of user is User | undefined (we can either set a user or undefined)
const [user, setUser] = useState<User>();
setUser({ firstName: "Pat", age: 23, role: UserRole.CTO });
setUser(undefined);

// the type of user is User | null (we can either set a user or null)
const [user, setUser] = useState<User | null>(null);
setUser({ firstName: "Pat", age: 23, role: UserRole.CTO });
setUser(null);
```

This should give you enough to work with `useState()`. As we focus on the minimal TypeScript skills for React we won’t discuss the other hooks here. Just note that `useEffect()` doesn’t need typing.

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/hooks-)

### Custom Hooks With TypeScript

A custom hook is again just a function. So you already know how to type it.

```typescript
function useFireUser(firstName: string) {
	const [isFired, setIsFired] = useState(false);
  const hireAndFire = () => setIsFired(!isFired);

	return {
    text: isFired ? `Oops, hire ${firstName} back!` : "Fire this loser!",
    hireAndFire,
  };
}

function UserProfile({ firstName, role }: UserProfileProps) {
  const { text, hireAndFire } = useFireUser(firstName);
  return (
    <>
      <div>Hi {firstName}, you suck!</div>
      <button onClick={hireAndFire}>
        {text}
      </button>
    </>
  );
}
```

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/custom-hooks-)

### React Events With TypeScript

Working with inline click handlers is simple as TypeScript knows the type of the event parameter already. You don’t need to type anything manually.

```typescript
function FireButton() {
  return (
    <button onClick={(event) => event.preventDefault()}>
      Fire this loser!
    </button>
  );
}
```

It becomes more complicated when you create separate click handlers though.

```typescript
function FireButton() {
  const onClick = (event: ???) => {
    event.preventDefault();
  };

  return (
    <button onClick={onClick}>
      Fire this loser!
    </button>
  );
}
```

What’s the type of `event` here? Here are two approaches:

1. Search on Google (can’t recommend, makes you dizzy).
2. Pretend you have an inline function and let TypeScript serve you the type on a silver platter.

![Hover over the inline function parameter to get the correct event type](no-optimization::https://media.graphassets.com/D0tOhvTjRe7ut5nWbwPF)

Happy copy & pasting. You don’t even need to understand what’s going on here (hint: these are generics as we saw them with `useState`).

```typescript
function FireButton() {
  const onClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    event.preventDefault();
  };

  return (
    <button onClick={onClick}>
      Fire this loser!
    </button>
  );
}
```

What about a change handler on an input? The same strategy reveals: 

```typescript
function Input() {
  const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    console.log(event.target.value);
  };

  return <input onChange={onChange} />;
}
```

And a select?

```typescript
function Select() {
  const onChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
    console.log(event.target.value);
  };

  return <select onChange={onChange}>...</select>;
}
```

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/events-)

### Children Type Or Component Type

As we’re all fans of component composition we need to know how to type the common `children` prop.

```typescript
type LayoutProps = {
  children: React.ReactNode;
};

function Layout({ children }: LayoutProps) {
  return <div>{children}</div>;
}
```

The type `React.ReactNode` gives you a lot of freedom. It basically lets us pass anything as a child (except an object).

![React.ReactNode type allows everything but objects](https://media.graphassets.com/OtOWIPJHTo6Q4R3depAA)

If we want to be a bit stricter and only allow markup we can use `React.ReactElement` or `JSX.Element` (which is basically the same).

```typescript
type LayoutProps = {
  children: React.ReactElement; // same as JSX.Element
};
```

As you can see, this is much more restrictive:

![React.ReactElement type allows only JSX](https://media.graphassets.com/EPiU1e1dSa6nRmjsdfHT)

[![React on the job - email course](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/skyncbvxln80rmks31wq.png)](https://profy.dev/around-react-email-workshop)

## Working With Third-Party Libraries

### Adding Types

Nowadays, many third-party libraries already ship with their corresponding types. In that case, you don’t need to install a separate package.

But many types are also maintained in the [DefinitelyTyped repository](https://github.com/DefinitelyTyped/DefinitelyTyped) on GitHub and published under the `@types` organization (even the React types). If you install a library without types you get an error message on the import statement.

![Many third-party libraries required additional types in the @types registry](https://media.graphassets.com/WnTIPfsaRHqAPoRUyAH2)

You can simply copy & paste the highlighted command and execute it in the terminal. 

```typescript
npm i --save-dev @types/styled-components
```

Most of the time, you’ll be lucky and the required types are available in some way or the other. Especially for more popular libraries. But if you’re not you can still define your own global types in a `.d.ts` file (we won’t cover this here though).

### Using Generics

Libraries often need to handle a lot of use cases. And thus they need to be flexible. To define flexible types generics are used. We’ve seen them with `useState` already. Here’s a reminder:

```typescript
const [names, setNames] = useState<string[]>([]);
```

This is very common in many third-party libraries. Here is Axios as an example:

```typescript
import axios from "axios"

async function fetchUser() {
  const response = await axios.get<User>("https://example.com/api/user");
  return response.data;
}
```

![third-party libraries often use generic types](https://media.graphassets.com/U2ctnTGZRhqrFPUJc11k)

Or react-query:

```typescript
import { useQuery } from "@tanstack/react-query";

function UserProfile() {
  // generic types for data and error
  const { data, error } = useQuery<User, Error>(["user"], () => fetchUser());

  if (error) {
    return <div>Error: {error.message}</div>;
  }

  ...
}
```

Or styled-components:

```typescript
import styled from "styled-components";

// generic type for props
const MenuItem = styled.li<{ isActive: boolean }>`
  background: ${(props) => (props.isActive ? "red" : "gray")};
`;

function Menu() {
  return (
    <ul>
      <MenuItem isActive>Menu Item 1</MenuItem>
    </ul>
  );
}
```

## Strategies & Troubleshooting

### Getting Started With React & TypeScript

Creating a new project with TypeScript is the easiest option. I recommend either creating a Vite + React + TypeScript or Next.js + TypeScript project.

```typescript
// for Vite run this command and select "react-ts"
npm create vite@latest

// for Next.js run
npx create-next-app@latest --ts
```

This will set you up completely automatically.

### Finding The Right Type

We’ve touched on that already but let me repeat it here: When in doubt (especially useful with events) just start typing an inline function and let TypeScript show you the correct type.

![Hover over the inline function parameter to get the correct event type](no-optimization::https://media.graphassets.com/nqvKhf6iQkmZHgTQX7uD)

You can do the same if you’re not sure how many parameters are available. Just write `(...args) =>`  and you get all parameters in an array.

![Use spread operator to get all function parameters](https://media.graphassets.com/3o0V27R3QcKQwQqkpg6F)

### Inspecting A Type

The easiest way of seeing all available fields on a type is by using the autocomplete feature of your IDE. Here by pressing CTRL + space (Windows) or Option + space (Mac).

![Inspecting a TypeScript type with autocomplete suggestions](https://media.graphassets.com/ODKygAOUScOOutZUxlij)

Sometimes you need to dig deeper though. This is simple (yet often confusing) by CTRL + click (Windows) or CMD + click (Mac) to go to the type definitions.

![Inspecting a TypeScript type by following the definitions](no-optimization::https://media.graphassets.com/Btci858yQvyV9DKKbZFE)

[![React on the job - email course](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/skyncbvxln80rmks31wq.png)](https://profy.dev/around-react-email-workshop)

### Reading Error Messages

One major problem when getting started with TypeScript is all the errors you encounter. All the things that can go wrong can drive you nuts. So it’s a good idea to get used to read the error messages. Let’s take this as an example:

```typescript
function Input() {
  return <input />;
}

function Form() {
  return (
    <form>
      <Input onChange={() => console.log("change")} />
    </form>
  );
}
```

You might see the problem already. Still, here is the error that TypeScript shows.

![TypeScript error message: prop is not defined](https://media.graphassets.com/mUGaKGZGReKvRAXrlbLL)

Time to get confused! What the heck does this mean? What is the type `IntrinsicAttributes`? When working with libraries (e.g. React itself) you’ll encounter many strange type names like this. 

My advice: ignore them for now.

The most important piece of information is in the last line:

```typescript
Property 'onChange' does not exist on type ...
```

Does that ring a bell? Look at the definition of the `<Input>` component:

```typescript
function Input() {
  return <input />;
}
```

It doesn’t have a prop called `onChange`. That’s what TypeScript is complaining about.

Now, this was a rather simple example. But what about this?

```typescript
const MenuItem = styled.li`
  background: "red";
`;

function Menu() {
  return <MenuItem isActive>Menu Item</MenuItem>;
}
```

![TypeScript error message: no overload matches this call](https://media.graphassets.com/Mt7OKYVbRL6klYbQT2U3)

Holy cow! It’s easy to be confused by the sheer amount of error output here. My favorite technique here is to scroll to the bottom of the message. More often than not the golden nugget is buried in there.

![TypeScript error message: no overload matches this call solution is at the bottom](no-optimization::https://media.graphassets.com/aDNYjiMlTKG1R92bjIIR)

```typescript
function UserProfile() {
  const { data, error } = useQuery(
    ["user"],
    {
      cacheTime: 100000,
    },
    () => fetchUser()
  );
}
```

<CodeEditor repo="typescript-tutorial" path="/src/errors" dependencies={{ "@tanstack/react-query": "^4.16.1", "axios": "^1.1.3", "styled-components": "^5.3.6", "@types/styled-components": "^5.1.26" }} hidePreview />

### Objects As Props For Cleaner Types

In the above example, the user data would usually come from an API. Let’s assume we have the `User` type defined outside of the component

```typescript
export type User = {
  firstName: string;
  role: UserRole;
}
```

The `UserProfile` component at the moment takes exactly this object as props.

```typescript
function UserProfile({ firstName, role }: User) { 
  ...
}
```

This might seem reasonable for now. And it’s in fact pretty easy to render this component when we have a ready-made user object.

```typescript
function UserPage() {
  const user = useFetchUser();
  return <UserProfile {...user} />;
}
```

But as soon as we want to add additional props that are not included in the `User` type we make our lives harder. Remember the `fireUserLOL` function from above? Let’s put it to use.

```typescript
function UserProfile({ firstName, role, fireUser }: User) {
  return (
    <>
      <div>Hi {firstName}, you suck!</div>
      <button onClick={() => fireUser({ firstName, role })}>
        Fire this loser!
      </button>
    </>
  );
}
```

But since the `fireUser` function isn’t defined on the `User` type we get an error.

![Mixing different props types](https://media.graphassets.com/tKvKLmbATR6x3anz5eiB)

To create the correct type we can use a so-called intersection type by combining two types with `&`. This basically takes all fields from two different types and merges them into a single type.

```typescript
type User = {
  firstName: string;
  role: UserRole;
}

// this is called an intersection
// UserProfileProps has all fields of both types
type UserProfileProps = User & {
	fireUser: (user: User) => void;
}

function UserProfile({ firstName, role, fireUser }: UserProfileProps) {
  return (
    <>
      <div>Hi {firstName}, you suck!</div>
      <button onClick={() => fireUser({ firstName, role })}>
        Fire this loser!
      </button>
    </>
  );
}
```

Instead of intersection types, it’s often cleaner to separate the types. In our case, we can use a user prop instead of directly accepting all the user fields.

```typescript
type User = {
  firstName: string;
  role: UserRole;
}

type UserProfileProps = {
  user: User;
	fireUser: (user: User) => void;
}

function UserProfile({ user, onClick }: UserProfileProps) {
  return (
    <>
      <div>Hi {user.firstName}, you suck!</div>
      <button onClick={() => fireUser(user)}>
        Fire this loser!
      </button>
    </>
  );
}
```

[![Live Coding Exercise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlzulz3vgt2bko8nsjhi.png)](https://profy.dev/article/react-typescript#typescript-tutorial-/src/cleaner-types-)

[![React on the job - email course](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/skyncbvxln80rmks31wq.png)](https://profy.dev/around-react-email-workshop)