TypeScript

TypeScript Best Practices and Design Patterns

12 min read
Mahmoud Amr
Mahmoud Amr
TypeScript Best Practices and Design Patterns

TypeScript Best Practices and Design Patterns

Learn how to write clean, type-safe TypeScript code using modern design patterns and best practices.

Type System Fundamentals

Advanced Types

Using utility types effectively:

type User = {
  id: number;
  name: string;
  email: string;
  settings: {
    theme: 'light' | 'dark';
    notifications: boolean;
  };
};

// Pick specific properties
type UserBasics = Pick<User, 'id' | 'name'>;

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

// Make properties required
type RequiredUser = Required<User>;

// Extract union type
type Theme = Extract<User['settings']['theme'], string>;

Generic Constraints

Creating flexible, type-safe functions:

interface HasId {
  id: number | string;
}

function findById<T extends HasId>(items: T[], id: T['id']): T | undefined {
  return items.find(item => item.id === id);
}

// Usage
const users: User[] = [/* ... */];
const user = findById(users, 1);

Design Patterns

The Builder Pattern

Type-safe builder implementation:

class RequestBuilder {
  private config: RequestInit = {};

  setMethod(method: 'GET' | 'POST' | 'PUT' | 'DELETE'): this {
    this.config.method = method;
    return this;
  }

  setHeaders(headers: HeadersInit): this {
    this.config.headers = headers;
    return this;
  }

  setBody<T>(body: T): this {
    this.config.body = JSON.stringify(body);
    return this;
  }

  build(): RequestInit {
    return this.config;
  }
}

// Usage
const request = new RequestBuilder()
  .setMethod('POST')
  .setHeaders({ 'Content-Type': 'application/json' })
  .setBody({ data: 'example' })
  .build();

Error Handling

Type-safe error handling:

class AppError extends Error {
  constructor(
    message: string,
    public code: number,
    public details?: Record<string, unknown>
  ) {
    super(message);
    this.name = 'AppError';
  }
}

function handleError(error: unknown): void {
  if (error instanceof AppError) {
    console.error(`[${error.code}] ${error.message}`);
    if (error.details) {
      console.error('Details:', error.details);
    }
  } else {
    console.error('Unknown error:', error);
  }
}

Best Practices

  1. Use strict compiler options
  2. Leverage type inference
  3. Implement proper error handling
  4. Write self-documenting code
  5. Use discriminated unions

Conclusion

Following these TypeScript best practices will help you write more maintainable and type-safe applications.

TypeScriptJavaScriptWeb DevelopmentProgramming