typescriptbeginner

Custom Error Classes

Create typed custom error classes with HTTP status codes, error codes, and structured error handling.

typescript
// Base application error
class AppError extends Error {
  constructor(
    message: string,
    public statusCode: number = 500,
    public code: string = 'INTERNAL_ERROR',
    public isOperational: boolean = true
  ) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

// Specific error types
class NotFoundError extends AppError {
  constructor(resource: string, id?: string | number) {
    super(
      id ? `${resource} with id '${id}' not found` : `${resource} not found`,
      404,
      'NOT_FOUND'
    );
  }
}

class ValidationError extends AppError {
  constructor(
    message: string,
    public fields: Record<string, string> = {}
  ) {
    super(message, 400, 'VALIDATION_ERROR');
  }
}

class UnauthorizedError extends AppError {
  constructor(message = 'Authentication required') {
    super(message, 401, 'UNAUTHORIZED');
  }
}

class ForbiddenError extends AppError {
  constructor(message = 'Insufficient permissions') {
    super(message, 403, 'FORBIDDEN');
  }
}

class ConflictError extends AppError {
  constructor(message: string) {
    super(message, 409, 'CONFLICT');
  }
}

class RateLimitError extends AppError {
  constructor(public retryAfter: number) {
    super('Too many requests', 429, 'RATE_LIMITED');
  }
}

// Type guard
function isAppError(error: unknown): error is AppError {
  return error instanceof AppError;
}

// Error response formatter
function formatError(error: unknown) {
  if (isAppError(error)) {
    return {
      status: error.statusCode,
      error: {
        code: error.code,
        message: error.message,
        ...(error instanceof ValidationError && { fields: error.fields }),
        ...(error instanceof RateLimitError && { retryAfter: error.retryAfter }),
      },
    };
  }
  return {
    status: 500,
    error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' },
  };
}

// Usage
try {
  throw new NotFoundError('User', 42);
} catch (e) {
  console.log(formatError(e));
}

try {
  throw new ValidationError('Invalid input', {
    email: 'Invalid email format',
    age: 'Must be at least 18',
  });
} catch (e) {
  console.log(formatError(e));
}

Use Cases

  • Structured API error responses
  • Type-safe error handling
  • Centralized error management

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.