TypeScript Lesson 12: Advanced Types
These advanced patterns appear in large codebases and library types. Knowing them makes you a TypeScript expert.
Mapped Types
// Transform every property of a type
type Optional<T> = { [K in keyof T]?: T[K] };
type Nullable<T> = { [K in keyof T]: T[K] | null };
type Flags<T> = { [K in keyof T]: boolean };
// These are essentially Partial, but show how it works under the hood
type UserFlags = Flags<User>;
// { id: boolean; name: boolean; email: boolean; ... }
Conditional Types
// T extends U ? TrueType : FalseType
type IsArray<T> = T extends any[] ? true : false;
type A = IsArray<string[]>; // true
type B = IsArray<string>; // false
// Extract element type from array
type ElementOf<T> = T extends (infer U)[] ? U : never;
type StringItem = ElementOf<string[]>; // string
type UserItem = ElementOf<User[]>; // User
Template Literal Types
type EventName = "click" | "focus" | "blur";
type HandlerName = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"
type CSSProperty = "margin" | "padding" | "border";
type CSSDirection = "top" | "right" | "bottom" | "left";
type CSSDirectional = `${CSSProperty}-${CSSDirection}`;
// "margin-top" | "margin-right" | ... | "border-left"
You completed the TypeScript course!
What to learn next:
- Next.js + TypeScript — Full-stack typed apps
- Zod — Runtime type validation
- tRPC — End-to-end type safety
🏋️ Practice Task
Build a type-safe event emitter using advanced types. EventMap maps event names to payload types. Typed on
💡 Hint: interface EventMap { login: {userId: number}; logout: void; error: {message: string} }. The K extends keyof EventMap ensures emit(“login”, {userId:1}) works but emit(“login”, {message:”x”}) errors.