Advanced: TypeScriptAdvanced7 min23 / 23

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.

the problem, then the fix
// 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

a generic interface + a constraint
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 arrays
Tip

You 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.

Quick check

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.
Practice challenges
Test yourself · earn XP
0/3
Predict the output#1

What type does `x` have?

predict-output
function identity<T>(v: T): T { return v; }
const x = identity('hello');
Fix the bug#2

Why prefer this generic over the `any` version `function first(arr: any[]): any`?

fix-bug
function first<T>(arr: T[]): T {
  return arr[0];
}
Fill in the blank#3

Complete the type parameter declaration.

function wrap(value: T): { value: T } {
  return { value };
}
Your turn
Practice exercise

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:

solution.js · editable