Generic React Components with TypeScript

When building applications, we often have to think about how to create reusable components, that also have a well-defined API. These components should work on a variety of types, instead of only handling just a single one. This is what makes them so flexible.

If you are using React with TypeScript, then creating generic React components can help you better reuse your components with multiple types. But what are generic React components anyway? What are generics in the first place?

Learn React with Udemy

What are Generics?

Generics in TypeScript lets you define components with a special type, that can accept multiple types instead of just one. At this point, you may ask, can’t I just use any? That should work with any type, right?

const fn = (param: any): any => param;
any.ts
Copied to clipboard!

This is true. However, while doing so, you lose information about what type is passed and what is returned. If you call this function in your code, you will notice that you don’t get a clear type definition for the function call. It only tells us that it accepts any type, and we don’t know what is returned.

Using the any type in TypeScript

We might also don’t want to restrict what types this function can take. Instead of going with any, we can turn the above function into a generic using the following:

const fn = <T>(param: T): T => param;
generic.ts
Copied to clipboard!

Using T is the common way to denote generics, but you can use any name you like. You can create generics using angle brackets. Now we can see that the type definitions are inferred, and we have all information about the passed and returned types.

Using generics in TypeScript

Generics In React

Now let’s focus our attention to React, and see how generics work in them. We will take a look at how we can use it for props, hooks, and to create generic components.

Generic props

To use generic props in React, we can use the built in React.FC type — which accepts a generic — and create an interface that we can pass as the props between angle brackets. This way, you will be able to get type definitions for your props:

interface Props {
    user: {
        name: string,
        email: Email
    }
}

const Component: React.FC<Props> = ({ user }) => {
    const { name, email } = user;

    return <div>You are logged in as {name} ({email})</div>;
};
Copied to clipboard!

Generic hooks

Just like props, you can also use generics with hooks. If you look into the type definitions of React, you will notice that the argument you can pass to hooks are generics. Notice in the code example below that you will get the right type definitions for the initial state:

const Component: React.FC<Props> = ({ user }) => {
    const [state] = useState(user);
    
    // ✔️ Works without an issue.
    return <div>You are logged in as {state.name}</div>;
    
    // ❌ TypeScript will throw an error as there is no fullName on the user state.
    return <div>You are logged in as {state.fullName}</div>;
};
Copied to clipboard!

You can also override generics by passing the type in angle brackets just before you set the initial value for the hook:

interface InitialState {
    user: {
        fullName: string
    }
}

const Component: React.FC<Props> = ({ user }) => {
    // Pass the type explicitly before calling the hook to override.
    const [state] = useState<InitialState>(user);

    ...
}
Copied to clipboard!

Generics components

Lastly, in some cases, you might want to create generic components in React. This is also possible with the following syntax:

interface Props<T> {
    items: T[]
}

const Components = <T extends InitialState>({ items }: Props<T>) => {
    
}
Copied to clipboard!

In this example, the interface takes in a generic with the value of T, and uses that value as the type for the items, which in this example, is an array. Also, note that you can extend generics with other types using the extends keyword, to give them a base type.

Learn React with Udemy

Summary

In summary, generics (not just in React), helps us create reusable components that can work over a variety of types, without losing information about the passed types along the way. Have you worked with generics before? Don’t forget to leave your thoughts in the comments below. Thank you for reading through, happy coding!

How to Get Started With TypeScript

📚 Get access to exclusive content

Want to get access to exclusive content? Support webtips to get access to tips, checklists, cheatsheets, and much more. ☕

Get access Support us
Read more on
🎉 Thank you for subscribing to our newsletter. x