TypeScript Handbook
Utility types, type patterns, and advanced TypeScript techniques for building type-safe applications.
TypeScript Handbook
Quick reference for TypeScript utility types and advanced patterns. Bookmark this page for type-safety recipes.
🏗️ Setup
Install and initialize TypeScript:
npm install typescript
npx tsc --init
VSCode Extensions
- BiomeJS (recommended): All-in-one formatter and linter
- Prettify TS Types: Display complex types in readable format
- TS/React/NextJS Snippets: Code snippet library
🔧 Object Manipulation
Pick and Omit
Extract or exclude properties from a type:
type User = { id: number; name: string; age: number; email: string };
type UserForm = Pick<User, 'name' | 'age'>;
type UserCore = Omit<User, 'age' | 'email'>;
Record: Typed Dictionaries
Map string keys to values with type safety:
type Roles = 'admin' | 'user' | 'guest';
type Permissions = Record<Roles, string[]>;
// Result: { admin: string[], user: string[], guest: string[] }
Partial and Required
Make all properties optional or required:
type PartialUser = Partial<User>; // all optional
type RequiredUser = Required<Partial<User>>; // all required
Readonly
Make properties immutable:
type ReadonlyUser = Readonly<User>;
// All properties are readonly
🔌 Function and Class Types
Extract Function Signatures
type Func = (name: string, age: number) => boolean;
type Params = Parameters<Func>; // [string, number]
type Return = ReturnType<Func>; // boolean
Constructor Types
class Database {
constructor(host: string, port: number) {}
}
type DBParams = ConstructorParameters<typeof Database>; // [string, number]
type DBInstance = InstanceType<typeof Database>; // Database
This Parameter Utilities
function sayHello(this: { name: string }, message: string) {}
type Context = ThisParameterType<typeof sayHello>; // { name: string }
type WithoutContext = OmitThisParameter<typeof sayHello>; // (message: string) => void
🔍 Type Filtering and Transformation
Extract and Exclude
Narrow unions to specific types:
type Colors = 'red' | 'green' | 'blue' | 'yellow';
type WarmColors = Extract<Colors, 'red' | 'yellow'>; // 'red' | 'yellow'
type CoolColors = Exclude<Colors, 'red' | 'yellow'>; // 'green' | 'blue'
NonNullable
Remove null and undefined:
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>; // string
Awaited
Unwrap Promise types:
type NestedPromise = Promise<Promise<number>>;
type Unwrapped = Awaited<NestedPromise>; // number
📝 String Manipulation
Case Transformation
type Greeting = 'hello world';
type Upper = Uppercase<Greeting>; // 'HELLO WORLD'
type Lower = Lowercase<Greeting>; // 'hello world'
type Cap = Capitalize<Greeting>; // 'Hello world'
type Uncap = Uncapitalize<'Hello'>; // 'hello'
Works with unions too:
type Animals = Uppercase<'cat' | 'dog'>; // 'CAT' | 'DOG'
🚀 Expert-Level Patterns
Mapped Types with Conditional Logic
type Concrete<Type> = {
[Property in keyof Type]-?: Type[Property];
};
type OptionalUser = { id?: number; name?: string };
type RequiredUser = Concrete<OptionalUser>; // { id: number; name: string }
Template Literal Types
type EventName = 'click' | 'scroll' | 'hover';
type HandlerName = `on${Capitalize<EventName>}`; // 'onClick' | 'onScroll' | 'onHover'
Key Remapping with as
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type User = { name: string; age: number };
type UserGetters = Getters<User>; // { getName: () => string; getAge: () => number }
Conditional Type Inference
type ArrayElement<T> = T extends (infer U)[] ? U : never;
type StringArrayElement = ArrayElement<string[]>; // string
🏢 Advanced Composition Patterns
Deep Partial
Make nested objects fully optional:
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
type Config = { db: { host: string; port: number }; api: { url: string } };
type PartialConfig = DeepPartial<Config>; // All nested properties optional
Union to Intersection
Convert union types to intersections:
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void
? I
: never;
type Result = UnionToIntersection<{ a: number } | { b: string }>;
// { a: number } & { b: string }
Extract Async Return Types
type AsyncReturn<T extends (...args: any) => any> = Awaited<ReturnType<T>>;
async function fetchUser() {
return { id: 1, name: 'John' };
}
type User = AsyncReturn<typeof fetchUser>; // { id: number; name: string }
Safe Dictionary Access
type SafeAccess<T, K extends PropertyKey> = K extends keyof T ? T[K] : never;
type UserName = SafeAccess<User, 'name'>; // string
type UserInvalid = SafeAccess<User, 'invalid'>; // never
💼 Real-World Pro Patterns
Complex Type Composition
type UpdateUser = Partial<Pick<User, 'name' | 'email'>>;
Type-Safe Async Function Wrapper
function wrapAsync<F extends (...args: any[]) => Promise<any>>(fn: F) {
return async (...args: Parameters<F>): Promise<Awaited<ReturnType<F>>> => {
return fn(...args);
};
}
Type-Safe Event System
type EventMap = {
click: MouseEvent;
keypress: KeyboardEvent;
custom: { data: string };
};
type EventHandler<T> = (event: T) => void;
type EventSystem = {
on<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): void;
emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void;
};
Builder Pattern with Type Safety
type Builder<T, K extends keyof T = keyof T> = K extends keyof T
? (value: T[K]) => Builder<Omit<T, K>> & { build(): T }
: { build(): T };
type Product = { name: string; price: number; category: string };
const product = createBuilder<Product>().name('Laptop').price(999).category('Electronics').build();
💡 Key Takeaways
- Pick and Omit handle 80% of type transformations
- Mapped types let you iterate over object properties programmatically
- Conditional types add logic to your types
- Template literal types generate union types from patterns
- Advanced patterns (Deep Partial, Union to Intersection) solve specific architectural problems