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.