Skip to main content

# Understanding TypeScript Generics: Write Flexible, Reusable Code

Updated 3 min readMarkdown

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:

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

This only works with strings.

With generics:

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

Now it works with any type:

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

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

Usage:

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

Generics in Interfaces

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

Usage:

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

Generics in Classes

class Box<T> {
  content: T

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

Usage:

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

Generic Constraints

Sometimes you want to limit what types can be used.

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

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

Usage:

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

Default Generic Types

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)

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

Usage:

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:

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.

1 view

About the author

  • I’m a passionate Software Developer with 2 years of hands-on experience building full-stack web applications that are clean, scalable, and user-friendly. With a strong foundation in modern frameworks like Laravel and Vue.js, I enjoy crafting digital solutions that not only work well but also deliver real value. My journey in software development has been driven by curiosity, creativity, and a love for solving real-world problems through code. Whether it's building RESTful APIs, designing responsive UIs, or optimizing performance, I’m always eager to learn, improve, and push boundaries. Currently, I’m focused on expanding my skills in Kibana, Elasticsearch, and scalable architecture for production-ready applications. 🚀 Let’s build something great together.

No comments yet. Be the first to comment.