TypeScript Handbook
My collection of TypeScript utility types.
Installation
npm install typescript
Setup and Configuration
npx tsc --init
VSCode Extensions
- Formatting and Linter
- Editor Helper
Utility Types
Object Manipulation
// Pick specific properties
type User = { id: number; name: string; age: number; email: string };
type UserForm = Pick<User, 'name' | 'age'>; // { name: string; age: number; }
// Omit properties
type UserCore = Omit<User, 'age' | 'email'>; // { id: number; name: string; }
// Create typed dictionaries
type Roles = 'admin' | 'user' | 'guest';
type Permissions = Record<Roles, string[]>; // { admin: string[], user: string[], guest: string[] }
// Make properties optional/required
type PartialUser = Partial<User>; // all properties become optional
type RequiredUser = Required<PartialUser>; // all properties required
// Create immutable objects
type ReadonlyUser = Readonly<User>; // all properties readonly
Function & Class Types
// Extract function parameters and return types
type Func = (name: string, age: number) => boolean;
type Params = Parameters<Func>; // [string, number]
type Return = ReturnType<Func>; // boolean
// Work with class constructors
class Database {
constructor(host: string, port: number) {}
}
type DBParams = ConstructorParameters<typeof Database>; // [string, number]
type DBInstance = InstanceType<typeof Database>; // Database
// ThisParameterType and related 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 & Transformation
// Filter union types
type Colors = 'red' | 'green' | 'blue' | 'yellow';
type WarmColors = Extract<Colors, 'red' | 'yellow'>; // 'red' | 'yellow'
type CoolColors = Exclude<Colors, 'red' | 'yellow'>; // 'green' | 'blue'
// Remove null/undefined
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>; // string
// Unwrap promises
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 Capitalized = Capitalize<Greeting>; // 'Hello world'
type Uncapitalized = Uncapitalize<'Hello World'>; // 'hello World'
// Works with unions too
type Animals = Uppercase<'cat' | 'dog'>; // 'CAT' | 'DOG'
Expert-Level Utilities
// Mapped type modifiers with conditions
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 for advanced patterns
type EventName = 'click' | 'scroll' | 'hover';
type HandlerName = `on${Capitalize<EventName>}`; // 'onClick' | 'onScroll' | 'onHover'
// Key remapping with as clause
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
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
// Function inference with multiple overloads
type FirstParameter<T> = T extends (arg: infer P, ...rest: any[]) => any ? P : never;
Advanced Composition Patterns
// Deep partial for nested objects
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
type NestedConfig = { db: { host: string; port: number }; api: { url: string } };
type PartialConfig = DeepPartial<NestedConfig>; // db and api become optional with nested properties optional
// Union to intersection
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 promise types from async functions
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
// Combine utilities for complex types
type UpdateUser = Partial<Pick<User, 'name' | 'email'>>;
// Safe function wrappers with inference preservation
function wrapAsync<F extends (...args: any[]) => Promise<any>>(fn: F) {
return async (...args: Parameters<F>): Promise<Awaited<ReturnType<F>>> => {
return fn(...args);
};
}
// Event system with type safety
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 };
function createBuilder<T>(): Builder<T> {
// implementation
}
// Usage:
type Product = { name: string; price: number; category: string };
const productBuilder = createBuilder<Product>().name('Laptop').price(999).category('Electronics').build(); // Type: Product
Bookmark this page for quick reference. More advanced patterns coming soon!