TypeScript Advanced Patterns for Modern Web Development

Master advanced TypeScript patterns including utility types, conditional types, template literals, and type-safe API design for production-ready applications.

2 min read
By Sagar Tank
TypeScriptProgrammingAdvanced PatternsType Safety
T
Image
TypeScript Advanced Patterns for Modern Web Development

TypeScript's type system goes far beyond basic type annotations. Advanced patterns enable you to create type-safe, maintainable codebases that catch errors at compile time.

Utility Types Deep Dive

TypeScript provides powerful utility types for common transformations:

Pick and Omit

interface User {
  id: string
  name: string
  email: string
  password: string
}

// Pick specific properties
type PublicUser = Pick<User, 'id' | 'name' | 'email'>

// Omit specific properties
type UserWithoutPassword = Omit<User, 'password'>

Partial and Required

// Make all properties optional
type PartialUser = Partial<User>

// Make all properties required
type RequiredUser = Required<PartialUser>

Conditional Types

Conditional types enable type-level logic:

type NonNullable<T> = T extends null | undefined ? never : T

type ApiResponse<T> = T extends string
  ? { message: T }
  : T extends number
  ? { code: T }
  : { data: T }

Template Literal Types

Create type-safe string patterns:

type Route = `/${string}`
type ApiEndpoint = `/api/${string}`

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
type ApiRoute = `${HttpMethod} ${ApiEndpoint}`

Mapped Types

Transform types programmatically:

type Readonly<T> = {
  readonly [P in keyof T]: T[P]
}

type Optional<T> = {
  [P in keyof T]?: T[P]
}

Type Guards and Assertions

Create runtime type checking:

function isString(value: unknown): value is string {
  return typeof value === 'string'
}

function assertIsNumber(value: unknown): asserts value is number {
  if (typeof value !== 'number') {
    throw new Error('Expected number')
  }
}

Generic Constraints

Constrain generic types:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}

interface Lengthwise {
  length: number
}

function logLength<T extends Lengthwise>(arg: T): T {
  console.log(arg.length)
  return arg
}

Branded Types

Create distinct types from primitives:

type UserId = string & { readonly brand: unique symbol }
type Email = string & { readonly brand: unique symbol }

function createUserId(id: string): UserId {
  return id as UserId
}

Conclusion

Advanced TypeScript patterns enable you to build type-safe applications with excellent developer experience. These patterns catch errors at compile time and make refactoring safer and easier.

Enjoyed this article?

Check out more articles on the blog or get in touch to discuss your project.