# # Understanding TypeScript Generics: Write Flexible, Reusable Code

When working with TypeScript, one of the most powerful features you’ll encounter is **generics**. If you've ever found yourself duplicating code just to handle different data types, generics are the solution you’ve been looking for.

Let’s break it down in a practical and developer-friendly way.

## What Are Generics?

Generics allow you to write code that works with **multiple types** instead of a single one. Think of them as placeholders for types.

Instead of saying:

> “This function only works with strings”

You say:

> “This function works with any type—and I’ll decide that type later.”

## Basic Example

Without generics:

```ts
function identity(value: string): string {
  return value
}
```

This only works with strings.

With generics:

```ts
function identity<T>(value: T): T {
  return value
}
```

Now it works with **any type**:

```ts
identity<string>("Hello")
identity<number>(42)
identity<boolean>(true)
```

* * *

## Why Use Generics?

### 1\. Reusability

You write code once and use it with different types.

### 2\. Type Safety

You still get full TypeScript type checking.

### 3\. Cleaner Code

No need to create multiple versions of the same function.

* * *

## Generics with Arrays

```ts
function getFirstItem<T>(arr: T[]): T {
  return arr[0]
}
```

Usage:

```ts
getFirstItem<number>([1, 2, 3])
getFirstItem<string>(["a", "b", "c"])
```

* * *

## Generics in Interfaces

```ts
interface ApiResponse<T> {
  data: T
  status: number
}
```

Usage:

```ts
const userResponse: ApiResponse<{ name: string }> = {
  data: { name: "Norman" },
  status: 200
}
```

* * *

## Generics in Classes

```ts
class Box<T> {
  content: T

  constructor(value: T) {
    this.content = value
  }
}
```

Usage:

```ts
const numberBox = new Box<number>(123)
const stringBox = new Box<string>("Hello")
```

* * *

## Generic Constraints

Sometimes you want to limit what types can be used.

```ts
function printLength<T extends { length: number }>(item: T): void {
  console.log(item.length)
}
```

This ensures only types with a `length` property are allowed.

* * *

## Multiple Generics

```ts
function pair<K, V>(key: K, value: V) {
  return { key, value }
}
```

Usage:

```ts
pair<string, number>("age", 25)
```

* * *

## Default Generic Types

```ts
function createArray<T = string>(length: number, value: T): T[] {
  return Array(length).fill(value)
}
```

If no type is provided, it defaults to `string`.

* * *

## Real-World Example (API Fetching)

```ts
async function fetchData<T>(url: string): Promise<T> {
  const response = await fetch(url)
  return response.json()
}
```

Usage:

```ts
type User = {
  id: number
  name: string
}

const user = await fetchData<User>("/api/user")
```

* * *

## Common Mistakes

### Overusing Generics

Don’t use generics when a specific type is enough.

### Ignoring Type Inference

TypeScript can often infer the type automatically:

```ts
identity("Hello") // no need for <string>
```

* * *

## When Should You Use Generics?

Use generics when:

*   You want reusable components/functions
    
*   You don’t know the type ahead of time
    
*   You want flexibility **without losing type safety**
    

* * *

## Final Thoughts

Generics are a game-changer in TypeScript. They help you write **cleaner, reusable, and safer code** especially in large-scale applications.
