---
title: "Understanding Generic Types in TypeScript"
description: "Learn how to use TypeScript generics with practical examples like paginated data, reusable React components, and Next.js page components."
slug: "understanding-generic-types-in-typescript"
url: "https://furkanbaytekin.dev/blogs/understanding-generic-types-in-typescript"
author: "Furkan Baytekin"
category: "Software"
tags: []
published: 2024-12-19T00:13:35Z
updated: 2024-12-19T00:13:35Z
readTime: 5
cover: "https://myblogcms.furkanbaytekin.dev/uploads/cover/understanding-generic-types-in-typescript+1734507541983"
---

TypeScript is a powerhouse when it comes to building scalable, maintainable applications. One of its standout features is the ability to define **generic types**, a tool that provides flexibility and reusability across various scenarios. In this blog, we’ll explore the concept of generics using some practical examples that illustrate their power and utility.

---

## What Are Generics?

Generics allow you to define components, functions, or types that can work with a variety of data types while maintaining type safety. Instead of hardcoding a specific type, generics let you use placeholders (like `T`, `Data`, or `Props`) to represent types, which are then replaced with actual types at runtime.

In essence, generics provide **type parameters** that make your code adaptable and reusable.

---

## Example 1: Creating a Paginated Type

Pagination is a common feature in applications. A generic type can help define a consistent shape for paginated responses, regardless of the data type being paginated. Here's how you can use generics for this purpose:

```typescript
type Paginated<Data> = {
  data: Data[]
  page: number
  take: number
  total: number
}
```

### Breaking It Down:
- `Data` is the generic type placeholder that represents the type of the paginated data.
- `data: Data[]` ensures that the `data` property is always an array of the specified type.
- Other properties like `page`, `take`, and `total` are standard fields in a paginated response.

### Example Usage:
Imagine you’re paginating a list of users and posts. With the `Paginated` type, you can handle both scenarios without duplicating code:

```typescript
type User = {
  id: number
  name: string
}

type Post = {
  id: number
  title: string
  content: string
}

// Paginated users
const paginatedUsers: Paginated<User> = {
  data: [
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" }
  ],
  page: 1,
  take: 10,
  total: 50
}

// Paginated posts
const paginatedPosts: Paginated<Post> = {
  data: [
    { id: 1, title: "Intro to TypeScript", content: "TypeScript is awesome!" },
    { id: 2, title: "Generics 101", content: "Learn how to use generics." }
  ],
  page: 2,
  take: 5,
  total: 20
}
```

By using generics, the `Paginated` type adapts seamlessly to different data types, maintaining strict type safety.

---

## Example 2: A Parent Component Type for React

In React, many components accept `children` as props. You can define a reusable type that ensures type safety for both the component's props and its children:

```typescript
type ParentComponent<Props = object> = Props & {
  children: React.ReactNode
}
```

### Breaking It Down:
- `Props = object` defines a generic type with a default value (`object`). If no specific type is provided, `Props` defaults to `object`.
- The `&` operator merges `Props` with `{ children: React.ReactNode }`, ensuring that any component using this type can handle additional props and children.

### Example Usage:
Here’s how you can use `ParentComponent` in a real-world scenario:

```typescript
type CardProps = {
  title: string
}

const Card: React.FC<ParentComponent<CardProps>> = ({
  title, children
}) => 
  <div className="card">
    <h2>{title}</h2>
    <div>{children}</div>
  </div>

// Using the Card component
<Card title="Welcome">
  <p>This is a reusable card component with generics.</p>
</Card>
```

This type ensures that:
1. The `title` prop is required for the `Card` component.
2. The `children` prop is always valid and type-safe.

---

## Example 3: Next.js Page Component with Context

Neneric types can make page components more robust by defining the structure of context and search parameters. Here’s a generic type to manage them:

```typescript
type PageComponent<Context = object> = {
  params: Promise<Context>
  searchParams: Promise<Record<string, string | undefined>>
}
```

> `Promise`s are required after version 15 in Next.js

### Breaking It Down:
- `Context = object` allows developers to specify the shape of the context object for the page.
- `params: Promise<Context>` ensures that `params` will always resolve to a value of type `Context`.
- `searchParams: Promise<Record<string, string | undefined>>` handles query parameters, mapping keys to strings or `undefined`.

### Example Usage:
Suppose you’re building a page that displays a blog post list based on its category slug. You can define a page component type like this:

```typescript
type CategoryContext = {
  category: string
}

// For the URL /blogs/software?sort=desc&filter=popular
const CategoryPage: React.FC<PageComponent<CategoryContext>> = async ({ 
  params, searchParams
}) => {
  const resolvedParams = await params
  const resolvedSearchParams = await searchParams

  console.log(resolvedParams) // { category: "typescript-generics" }
  console.log(resolvedSearchParams) // { sort: "desc", filter: "popular" }

  return <div>
    <h1>Slug: {resolvedParams.slug}</h1>
    <p>Sort: {resolvedSearchParams.sort}</p>
  </div>
}
```

This ensures type safety when accessing the `params` and `searchParams`, reducing runtime errors and improving code readability.

---

## Why Use Generics?

- **Reusability**: Generic types can be applied to various data structures or components, reducing redundancy.
- **Type Safety**: They provide stricter type checking, catching potential errors during development.
- **Flexibility**: Generics allow you to handle diverse use cases without sacrificing maintainability.

---

## Conclusion

Generics are a fundamental part of TypeScript that make your code more reusable, flexible, and maintainable. Whether you're handling paginated data, building reusable React components, or managing complex contexts in Next.js, generics can simplify and strengthen your codebase.

The examples above highlight the versatility of generics in TypeScript. By embracing this feature, you can write cleaner, safer, and more adaptable code that scales with your application’s needs.
