Skip to content

Generics Basics

A generic lets a function, class, or type work with multiple types while preserving the connection between them β€” instead of writing separate versions for number, string, etc. (or giving up and using any), you use a type parameter (conventionally T) that gets filled in with a concrete type at each call site.

function identity<T>(value: T): T {
return value;
}
identity<number>(42); // T is number, returns number
identity("hello"); // T inferred as string, returns string
function firstItem<T>(items: T[]): T | undefined {
return items[0];
}
firstItem([1, 2, 3]); // number | undefined
firstItem(["a", "b"]); // string | undefined
class Box<T> {
constructor(private value: T) {}
getValue(): T {
return this.value;
}
}
const numberBox = new Box<number>(42);
const stringBox = new Box("hello"); // T inferred as string

Using any instead of a generic when a function’s input and output types are actually related β€” any loses that connection entirely, so TypeScript can no longer verify the return value matches what was passed in.

function firstItem(items: any[]): any {
return items[0];
}
const result = firstItem([1, 2, 3]);
result.toUpperCase(); // no compile error, but crashes at runtime -- result is a number!
// With a generic, the relationship between input and output is preserved
function firstItem<T>(items: T[]): T {
return items[0];
}
const result = firstItem([1, 2, 3]); // TypeScript knows result: number
result.toUpperCase(); // Error caught at compile time: Property 'toUpperCase' does not exist on type 'number'
  1. What problem do generics solve that any doesn’t?

    AnswerGenerics preserve the relationship between input and output types, so TypeScript can still catch type errors; any discards type information entirely, losing that safety.
  2. In function identity<T>(value: T): T, what determines what T becomes at a given call site?

    AnswerEither an explicit type argument (identity<number>(42)) or, more commonly, TypeScript infers it automatically from the argument you pass.
  3. What does class Box<T> let you do that a non-generic class Box couldn’t?

    AnswerCreate boxes that hold and return a specific, type-checked value type (Box<number>, Box<string>, etc.) using one shared implementation, instead of writing a separate class per type or losing type safety with any.