Introduction
React in combination with TypeScript is an effective way of building modern web applications. As TypeScript supports generics, those can also be used for React components. In this blog post, I am going to demonstrate the concept of generic functional React components with TypeScript. As a practical example we will create a generic list component that is able to render any kind of items.
What are generics?
Generics in TypeScript empore functions, components and classes to work with different types of data without loosing their type safety. They yield a technique to design software as flexible and reusable as possible.
Generic list component
To illustrate the concept of generic components we are going to implement a list that can render items of various data types. In our case fruits.
Generic type
To define the API of the generic list component we create a GenericListProps
type that contains the following properties:
Property | Description |
---|---|
items | The array of items to render |
createKey | A function to create the special key attribute you need to include when creating a list |
renderItems | A function that returns a ReactNode based on the current item |
GenericListProps
has to be parameterized to support items of different types of data. Therefore, we apply a TypeScript generic, denoted as <T>
. This generic is used throughout GenericListProps
:
import { Key, ReactNode } from 'react';
type GenericListProps<T> = {
items: T[];
createKey: (item: T) => Key;
renderItem: (item: T) => ReactNode;
};
Through that, items
, createKey
and renderItem
are not limited to a specific type.
Component
After defining GenericListProps
, let’s focus on the corresponding GenericList
component. Besides typehinting its props with GenericListProps<T>
, the same type parameter T
is used to make the component generic itself:
export const GenericList = <T,>(props: GenericListProps<T>) => {
const { items, createKey, renderItem } = props;
return (
<ul>
{items.map(item => (
<li key={createKey(item)}>{renderItem(item)}</li>
))}
</ul>
);
};
Usage
const FRUITS = [
{ id: 1, name: 'Apple', color: '#ff0000' },
{ id: 2, name: 'Avocado', color: '#00ff00' },
{ id: 3, name: 'Blueberry', color: '#4f86f7' },
];
export const Fruits = () => (
<GenericList
items={FRUITS}
createKey={fruit => fruit.id}
renderItem={fruit => <span style={{ color: fruit.color }}>{fruit.name}</span>}
/>
);
In the example above, the GenericList
component is used to render different fruits:
- Apple
- Avocado
- Blueberry
To create the special key
attribute, createKey
is given a function that returns the ID of each respective fruit. The function passed into renderItem
is creating a span
colorized based on the color of the fruit.
Conclusion
In this blog post I described how TypeScript generics can be used to build functional React components. It is a powerful tool that helps reducing code and enables components to handle a variety of data types, making them highly flexible and reusable.