Lesson 5 / 7

Generics

Generics let a function, interface, or class work with any type while TypeScript still tracks and checks exactly which type is being used each time — the same core idea covered in the Java and C++ courses on this site, adapted to TypeScript’s syntax.

function firstItem<T>(items: T[]): T {n    return items[0];n}nnconst firstCourse = firstItem(["Python", "TypeScript"]);   // inferred as stringnconst firstScore = firstItem([90, 85, 78]);                  // inferred as number

T is a placeholder type parameter, filled in automatically based on what you actually pass in — firstItem works correctly and type-safely for an array of any type, without writing a separate version for strings, numbers, and everything else.

Generic interfaces

interface ApiResponse<T> {n    data: T;n    success: boolean;n}nnconst courseResponse: ApiResponse<{ title: string }> = {n    data: { title: "TypeScript" },n    success: true,n};

This pattern shows up constantly in real code — an API response wrapper is a great example, since the wrapper shape (data, success) stays the same no matter what kind of data is actually being returned.

Constraining a generic type

interface HasLength {n    length: number;n}nnfunction logLength<T extends HasLength>(item: T): void {n    console.log(item.length);n}nnlogLength("hello");        // OK -- strings have .lengthnlogLength([1, 2, 3]);      // OK -- arrays have .lengthnlogLength(42);              // Error -- numbers don't have .length

extends HasLength restricts T to only types that actually have a length property, rather than accepting literally anything — this is the TypeScript equivalent of the bounded generics covered in the Java course.