Generics Basics

Generics allow you to write flexible, reusable code components that work across multiple data types while maintaining 100% type safety.

1. Why Use Generics?

Without generics, you either have to duplicate code for every data type or use any, which destroys type safety:

Without Generics (Loses Type Safety):
function getFirst(items: any[]): any {
  return items[0];
}

const num = getFirst([10, 20]); // Type is 'any'
With Generics (100% Type Safe):
function getFirst<T>(items: T[]): T {
  return items[0];
}

const num = getFirst<number>([10, 20]); // Type is 'number'!
const str = getFirst(["a", "b"]);      // Type is 'string'!

2. Generic Interfaces

Create reusable API response wrappers that accept any payload data shape:

interface ApiResponse<T> {
  status: number;
  message: string;
  data: T;
}

interface User { id: number; name: string }

// Reusing ApiResponse for User payload!
const response: ApiResponse<User> = {
  status: 200,
  message: "Success",
  data: { id: 1, name: "Alice" }
};

3. Generic Classes

class DataHolder<T> {
  private data: T[] = [];

  add(item: T) { this.data.push(item); }
  getAll(): T[] { return this.data; }
}

const numberStack = new DataHolder<number>();
numberStack.add(100);
numberStack.add(200);

Next Up

Learn Generic Constraints using `extends` and the `keyof` operator.

Next Lesson: Generic Constraints & keyof →