Advanced TypeScript
Generics, utility types, and narrowing — types that scale with your code.
- Write reusable code with generics
- Reshape types with utility types
- Let TypeScript narrow unions through control flow
The TypeScript basics lesson covered annotations and interfaces. The type system goes much further — letting you write code that's both reusable and precisely typed. These are the tools that make types help rather than fight you on a large codebase.
Generics: reusable and type-safe
A generic is a type parameter — it lets a function or type work over any
type while preserving it, rather than falling back to any:
function first<T>(items: T[]): T | undefined {
return items[0];
}
first([1, 2, 3]); // inferred as number
first(["a", "b"]); // inferred as stringT is filled in per call, so first works for every element type while still
knowing exactly what it returns. This is how Array, Promise<T>, and most
library types stay both flexible and safe.
Utility types
TypeScript ships utility types that transform existing types, so you don't repeat yourself:
interface User { id: number; name: string; email: string; }
Partial<User> // all fields optional
Pick<User, "id" | "name"> // just those fields
Omit<User, "email"> // everything except email
Readonly<User> // all fields read-onlyDerive related types from one source of truth instead of hand-writing each variant — the DRY principle at the type level.
Narrowing
TypeScript narrows a union type as it follows your control flow, so each branch knows the precise type:
function format(id: string | number): string {
if (typeof id === "string") {
return id.toUpperCase(); // here, TypeScript knows id is a string
}
return id.toFixed(0); // here, it knows id is a number
}The compiler reads your if/typeof checks and refines the type accordingly —
this is what makes unions (the data-and-types idea) pleasant to work with, forcing
you to handle each case.
Resist over-engineering types. Reach for advanced features when they remove real duplication or catch real bugs — not to show off. Clear, slightly-repetitive types beat a clever one nobody can read (the clarity-over-cleverness rule).
Where to go next
Last in the track: proving JavaScript and TypeScript code works — testing JavaScript.