runtime.boot

Full Stack Systems
Production Mindset

CodeWithMihir

Engineering thoughtful products from interface to infrastructure.

CodeWithMihir

TypeScript Tutorial

Real-world TypeScript Generic Examples

Learn real-world generic examples in TypeScript, including API clients, repositories, form helpers, result types, and reusable data models.

Welcome back! I am Mihir, and in this lesson we will look at real-world generic examples in TypeScript.

Generics are not only theory. You will use them constantly in real apps.


Generic API Function

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

Usage:

type User = {
  id: number;
  name: string;
};

const user = await fetchJson<User>("/api/user/1");

Now TypeScript knows user has id and name.


Generic API Response

type ApiResponse<T> = {
  success: boolean;
  data: T;
  error?: string;
};

type Product = {
  id: number;
  name: string;
  price: number;
};

type ProductResponse = ApiResponse<Product>;

This keeps response structure consistent across your app.


Generic Repository

interface Repository<T> {
  findAll(): T[];
  findById(id: number): T | undefined;
  save(item: T): void;
}

class MemoryRepository<T extends { id: number }> implements Repository<T> {
  private items: T[] = [];

  findAll(): T[] {
    return this.items;
  }

  findById(id: number): T | undefined {
    return this.items.find((item) => item.id === id);
  }

  save(item: T): void {
    this.items.push(item);
  }
}

The constraint ensures every item has an id.


Generic Form Field

type FormField<T> = {
  value: T;
  error?: string;
  touched: boolean;
};

const emailField: FormField<string> = {
  value: "mihir@example.com",
  touched: false,
};

const ageField: FormField<number> = {
  value: 28,
  touched: true,
};

Different fields can store different value types.


Generic Result Type

type Result<T> =
  | { success: true; data: T }
  | { success: false; error: string };

Usage:

function getUser(): Result<User> {
  return {
    success: true,
    data: {
      id: 1,
      name: "Mihir",
    },
  };
}

This pattern works well for operations that can fail.


Generic Select Option

type SelectOption<T> = {
  label: string;
  value: T;
};

const roleOptions: SelectOption<"admin" | "user">[] = [
  { label: "Admin", value: "admin" },
  { label: "User", value: "user" },
];

The option label is always a string, but the value can be flexible.


Quick Recap

  • Generics are useful in APIs, repositories, forms, and UI models.
  • Generic wrappers keep repeated structures clean.
  • Constraints make generic helpers safer.
  • Generic union types can model success and failure cleanly.
  • Real projects use generics to keep flexibility without losing type safety.

Next up, we start utility types with Partial →.