TypeScript: Generics
Write reusable code that works with any type while keeping full type safety — the <T> type parameter.
Sometimes a function or structure should work with any type, but you still want the types to line up. Generics let you write a placeholder type — usually T — that the caller fills in. It's like a parameter, but for types.
// Using 'any' loses all type safety:
function firstAny(arr: any[]): any { return arr[0]; }
// Generic: T is inferred from the argument
function first<T>(arr: T[]): T {
return arr[0];
}
const n = first([1, 2, 3]); // n: number
const s = first(["a", "b"]); // s: string
console.log(n, s);
// n.toFixed(2) is allowed; s.toUpperCase() is allowed —
// TS knows each one's real type<T> declares a type variable. When you call first([1,2,3]), TS infers T = number, so the return type is number — not any. You keep reuse and type safety.
#Generic types & constraints
interface Box<T> {
value: T;
}
const nb: Box<number> = { value: 42 };
// constrain T to things that have a .length
function longest<T extends { length: number }>(a: T, b: T): T {
return a.length >= b.length ? a : b;
}
console.log(longest("hello", "hi")); // works on strings
console.log(longest([1,2,3], [1])); // and arraysYou already use generics
Array<number>, Promise<string>, Map<string, User> are all generics from the standard library. Reach for your own generic when you catch yourself writing any just to make a function accept multiple types.
Why prefer a generic `<T>` over using `any`?
Key takeaways
- Generics (`<T>`) are type parameters — reusable code that keeps exact types.
- TS infers the type argument from how you call the function.
- Prefer a generic over `any`, which discards all type information.
- Constrain a generic with `T extends Shape`; `Array<T>`, `Promise<T>`, `Map<K,V>` are built-in generics.
What type does `x` have?
function identity<T>(v: T): T { return v; }
const x = identity('hello');Why prefer this generic over the `any` version `function first(arr: any[]): any`?
function first<T>(arr: T[]): T {
return arr[0];
}Complete the type parameter declaration.
function wrap(value: T): { value: T } { return { value }; }
Write a generic function wrap<T>(value: T) that returns { value } typed as { value: T }. wrap('hi') should have type { value: string }.
Try it live — edit the code and hit Run to see the output: