TypeScript Handbook

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

  1. Pick and Omit handle 80% of type transformations
  2. Mapped types let you iterate over object properties programmatically
  3. Conditional types add logic to your types
  4. Template literal types generate union types from patterns
  5. Advanced patterns (Deep Partial, Union to Intersection) solve specific architectural problems

📚 Resources