Примеры Обработки Ошибок Web TypeScript

Примеры обработки ошибок Web TypeScript включая перехват исключений, логирование и валидацию параметров

💻 Перехват Исключений typescript

🟢 simple ⭐⭐⭐

Обработка исключений try-catch, кастомные классы ошибок и распространение ошибок

⏱️ 20 min 🏷️ typescript, web, error handling
Prerequisites: Basic TypeScript, Error handling
// Web TypeScript Exception Catching Examples
// Try-catch blocks, custom errors, and error handling patterns

// 1. Basic Try-Catch Handler
class TryCatchHandler {
  // Safe execute with default value
  safeExecute<T>(fn: () => T, defaultValue: T): T {
    try {
      return fn();
    } catch (error) {
      console.error('Error in safeExecute:', error);
      return defaultValue;
    }
  }

  // Safe async execute
  async safeExecuteAsync<T>(fn: () => Promise<T>, defaultValue: T): Promise<T> {
    try {
      return await fn();
    } catch (error) {
      console.error('Error in safeExecuteAsync:', error);
      return defaultValue;
    }
  }

  // Execute with error callback
  executeWithCallback<T>(
    fn: () => T,
    onError: (error: unknown) => void
  ): T | null {
    try {
      return fn();
    } catch (error) {
      onError(error);
      return null;
    }
  }

  // Multiple try attempts
  async tryMultipleTimes<T>(
    fn: () => Promise<T>,
    attempts: number = 3,
    delay: number = 1000
  ): Promise<T> {
    for (let i = 0; i < attempts; i++) {
      try {
        return await fn();
      } catch (error) {
        if (i === attempts - 1) {
          throw error;
        }
        console.log(`Attempt ${i + 1} failed, retrying...`);
        await this.sleep(delay);
      }
    }
    throw new Error('All attempts failed');
  }

  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// 2. Custom Error Classes
class CustomError extends Error {
  constructor(
    message: string,
    public code: string,
    public statusCode: number = 500,
    public details?: any
  ) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace?.(this, this.constructor);
  }
}

class ValidationError extends CustomError {
  constructor(message: string, details?: any) {
    super(message, 'VALIDATION_ERROR', 400, details);
  }
}

class AuthenticationError extends CustomError {
  constructor(message: string) {
    super(message, 'AUTH_ERROR', 401);
  }
}

class NotFoundError extends CustomError {
  constructor(resource: string, id?: string) {
    super(
      `${resource}${id ? ` with ID '${id}'` : ''} not found`,
      'NOT_FOUND',
      404
    );
  }
}

class NetworkError extends CustomError {
  constructor(message: string, public originalError?: Error) {
    super(message, 'NETWORK_ERROR', 0);
  }
}

class PermissionError extends CustomError {
  constructor(resource: string, action: string) {
    super(
      `Permission denied to ${action} ${resource}`,
      'PERMISSION_ERROR',
      403
    );
  }
}

// 3. Error Boundary Pattern
class ErrorBoundary {
  private errorHandler?: (error: Error) => void;

  constructor(errorHandler?: (error: Error) => void) {
    this.errorHandler = errorHandler;
  }

  // Wrap function with error boundary
  wrap<T extends (...args: any[]) => any>(fn: T): T {
    return ((...args: any[]) => {
      try {
        return fn(...args);
      } catch (error) {
        this.handleError(error as Error);
        return null;
      }
    }) as T;
  }

  // Wrap async function
  wrapAsync<T extends (...args: any[]) => Promise<any>>(fn: T): T {
    return (async (...args: any[]) => {
      try {
        return await fn(...args);
      } catch (error) {
        this.handleError(error as Error);
        return null;
      }
    }) as T;
  }

  // Handle error
  private handleError(error: Error): void {
    if (this.errorHandler) {
      this.errorHandler(error);
    } else {
      console.error('ErrorBoundary caught error:', error);
    }
  }
}

// 4. Error Handler Chain
class ErrorHandlerChain {
  private handlers: Array<(error: Error) => boolean> = [];

  // Add handler to chain
  addHandler(handler: (error: Error) => boolean): this {
    this.handlers.push(handler);
    return this;
  }

  // Handle error through chain
  handle(error: Error): void {
    for (const handler of this.handlers) {
      const handled = handler(error);
      if (handled) {
        return;
      }
    }

    // No handler handled the error
    console.error('Unhandled error:', error);
  }

  // Create common handler chain
  static createDefault(): ErrorHandlerChain {
    return new ErrorHandlerChain()
      .addHandler((error) => {
        if (error instanceof ValidationError) {
          console.warn('Validation error:', error.message);
          return true;
        }
        return false;
      })
      .addHandler((error) => {
        if (error instanceof AuthenticationError) {
          console.warn('Authentication error:', error.message);
          // Redirect to login
          return true;
        }
        return false;
      })
      .addHandler((error) => {
        if (error instanceof NotFoundError) {
          console.warn('Not found:', error.message);
          return true;
        }
        return false;
      })
      .addHandler((error) => {
        if (error instanceof NetworkError) {
          console.error('Network error:', error.message);
          return true;
        }
        return false;
      });
  }
}

// 5. Error Recovery Manager
class ErrorRecoveryManager {
  // Execute with fallback
  async withFallback<T>(
    primaryFn: () => Promise<T>,
    fallbackFn: () => Promise<T>
  ): Promise<T> {
    try {
      return await primaryFn();
    } catch (primaryError) {
      console.warn('Primary function failed, using fallback:', primaryError);
      try {
        return await fallbackFn();
      } catch (fallbackError) {
        console.error('Fallback function also failed:', fallbackError);
        throw new Error('Both primary and fallback functions failed');
      }
    }
  }

  // Execute with multiple fallbacks
  async withMultipleFallbacks<T>(
    ...fns: Array<() => Promise<T>>
  ): Promise<T> {
    for (let i = 0; i < fns.length; i++) {
      try {
        return await fns[i]();
      } catch (error) {
        console.warn(`Function ${i + 1} failed:`, error);
        if (i === fns.length - 1) {
          throw error;
        }
      }
    }
    throw new Error('All functions failed');
  }

  // Execute with circuit breaker
  async withCircuitBreaker<T>(
    fn: () => Promise<T>,
    options: {
      failureThreshold?: number;
      recoveryTimeout?: number;
    } = {}
  ): Promise<T> {
    const {
      failureThreshold = 5,
      recoveryTimeout = 60000
    } = options;

    let failures = 0;
    let lastFailureTime = 0;
    let circuitOpen = false;

    return async (...args: any[]) => {
      if (circuitOpen) {
        const timeSinceLastFailure = Date.now() - lastFailureTime;

        if (timeSinceLastFailure < recoveryTimeout) {
          throw new Error('Circuit breaker is open');
        } else {
          circuitOpen = false;
          failures = 0;
        }
      }

      try {
        const result = await fn(...args);
        failures = 0;
        return result;
      } catch (error) {
        failures++;
        lastFailureTime = Date.now();

        if (failures >= failureThreshold) {
          circuitOpen = true;
          console.error('Circuit breaker opened after', failures, 'failures');
        }

        throw error;
      }
    };
  }
}

// 6. Error Context Manager
class ErrorContext {
  private context: Map<string, any> = new Map();

  // Set context value
  set(key: string, value: any): void {
    this.context.set(key, value);
  }

  // Get context value
  get(key: string): any {
    return this.context.get(key);
  }

  // Create error with context
  createError(message: string, errorClass?: new (...args: any[]) => Error): Error {
    const error = errorClass
      ? new errorClass(message)
      : new Error(message);

    (error as any).context = Object.fromEntries(this.context);

    return error;
  }

  // Wrap function with context
  withContext<T extends (...args: any[]) => any>(
    fn: T,
    contextData: Record<string, any>
  ): T {
    return ((...args: any[]) => {
      // Add context
      for (const key in contextData) {
        this.set(key, contextData[key]);
      }

      try {
        return fn(...args);
      } catch (error) {
        // Attach context to error
        (error as any).context = Object.fromEntries(this.context);
        throw error;
      }
    }) as T;
  }

  // Clear context
  clear(): void {
    this.context.clear();
  }
}

// 7. Global Error Handler
class GlobalErrorHandler {
  private handlers: Array<(error: ErrorEvent) => void> = [];

  // Setup global error handlers
  setup(): void {
    window.addEventListener('error', (event) => {
      this.handleError(new Error(event.message), event);
    });

    window.addEventListener('unhandledrejection', (event) => {
      this.handleError(event.reason, event);
    });
  }

  // Add custom handler
  addHandler(handler: (error: ErrorEvent) => void): void {
    this.handlers.push(handler);
  }

  // Handle error
  private handleError(error: Error, originalEvent?: any): void {
    console.error('Global error handler caught:', error);

    // Call custom handlers
    for (const handler of this.handlers) {
      try {
        handler({ error } as ErrorEvent);
      } catch (handlerError) {
        console.error('Error in error handler:', handlerError);
      }
    }
  }
}

// Usage Examples
async function demonstrateExceptionCatching() {
  console.log('=== Web TypeScript Exception Catching Examples ===\n');

  const tryCatch = new TryCatchHandler();
  const errorBoundary = new ErrorBoundary();
  const handlerChain = ErrorHandlerChain.createDefault();
  const recoveryManager = new ErrorRecoveryManager();
  const errorContext = new ErrorContext();

  // 1. Basic try-catch
  console.log('--- 1. Basic Try-Catch ---');
  const result = tryCatch.safeExecute(
    () => {
      console.log('Executing risky operation...');
      if (Math.random() > 0.5) {
        throw new Error('Random error occurred!');
      }
      return 'Success';
    },
    'Default Value'
  );
  console.log(`Result: ${result}`);

  // 2. Custom errors
  console.log('\n--- 2. Custom Errors ---');
  try {
    throw new ValidationError('Invalid input', { field: 'email', value: 'invalid' });
  } catch (error) {
    if (error instanceof ValidationError) {
      console.log(`Validation error: ${error.message}`);
      console.log(`Code: ${error.code}`);
      console.log(`Details: ${JSON.stringify(error.details)}`);
    }
  }

  // 3. Error boundary
  console.log('\n--- 3. Error Boundary ---');
  const safeFunction = errorBoundary.wrap(() => {
    throw new Error('This error will be caught');
  });
  safeFunction();

  // 4. Error handler chain
  console.log('\n--- 4. Error Handler Chain ---');
  handlerChain.handle(new ValidationError('Validation failed'));
  handlerChain.handle(new NotFoundError('User', '123'));

  // 5. Error recovery
  console.log('\n--- 5. Error Recovery ---');
  const recoveredResult = await recoveryManager.withFallback(
    async () => {
      throw new Error('Primary failed');
    },
    async () => {
      console.log('Using fallback...');
      return 'Fallback Result';
    }
  );
  console.log(`Recovered result: ${recoveredResult}`);

  // 6. Error context
  console.log('\n--- 6. Error Context ---');
  const contextualFn = errorContext.withContext(
    () => {
      throw new Error('Error with context');
    },
    { userId: '123', action: 'delete' }
  );

  try {
    contextualFn();
  } catch (error: any) {
    console.log(`Error context: ${JSON.stringify((error as any).context)}`);
  }

  console.log('\n=== All Exception Catching Examples Completed ===');
}

// Export functions
export { TryCatchHandler, CustomError, ValidationError, AuthenticationError, NotFoundError, NetworkError, PermissionError, ErrorBoundary, ErrorHandlerChain, ErrorRecoveryManager, ErrorContext, GlobalErrorHandler };
export { demonstrateExceptionCatching };

💻 Логирование typescript

🟡 intermediate ⭐⭐⭐

Реализация систем логирования с множественными уровнями, выводами и форматтерами

⏱️ 25 min 🏷️ typescript, web, error handling, logging
Prerequisites: Intermediate TypeScript, IndexedDB
// Web TypeScript Log Recording Examples
// Comprehensive logging system with multiple levels and outputs

// 1. Log Level Enum
enum LogLevel {
  DEBUG = 0,
  INFO = 1,
  WARN = 2,
  ERROR = 3,
  FATAL = 4
}

// 2. Log Entry Interface
interface LogEntry {
  timestamp: Date;
  level: LogLevel;
  message: string;
  context?: Record<string, any>;
  error?: Error;
  stack?: string;
}

// 3. Basic Logger
class Logger {
  private minLevel: LogLevel = LogLevel.INFO;
  private outputs: LogOutput[] = [];

  // Set minimum log level
  setMinLevel(level: LogLevel): void {
    this.minLevel = level;
  }

  // Add log output
  addOutput(output: LogOutput): void {
    this.outputs.push(output);
  }

  // Remove log output
  removeOutput(output: LogOutput): void {
    const index = this.outputs.indexOf(output);
    if (index > -1) {
      this.outputs.splice(index, 1);
    }
  }

  // Log at debug level
  debug(message: string, context?: Record<string, any>): void {
    this.log(LogLevel.DEBUG, message, context);
  }

  // Log at info level
  info(message: string, context?: Record<string, any>): void {
    this.log(LogLevel.INFO, message, context);
  }

  // Log at warn level
  warn(message: string, context?: Record<string, any>): void {
    this.log(LogLevel.WARN, message, context);
  }

  // Log at error level
  error(message: string, error?: Error, context?: Record<string, any>): void {
    this.log(LogLevel.ERROR, message, context, error);
  }

  // Log at fatal level
  fatal(message: string, error?: Error, context?: Record<string, any>): void {
    this.log(LogLevel.FATAL, message, context, error);
  }

  // Internal log method
  private log(
    level: LogLevel,
    message: string,
    context?: Record<string, any>,
    error?: Error
  ): void {
    if (level < this.minLevel) {
      return;
    }

    const entry: LogEntry = {
      timestamp: new Date(),
      level,
      message,
      context,
      error
    };

    if (error?.stack) {
      entry.stack = error.stack;
    }

    for (const output of this.outputs) {
      output.write(entry);
    }
  }

  // Create child logger with additional context
  child(context: Record<string, any>): ChildLogger {
    return new ChildLogger(this, context);
  }
}

// 4. Child Logger
class ChildLogger {
  constructor(
    private parent: Logger,
    private context: Record<string, any>
  ) {}

  debug(message: string, additionalContext?: Record<string, any>): void {
    this.parent.debug(
      message,
      additionalContext ? { ...this.context, ...additionalContext } : this.context
    );
  }

  info(message: string, additionalContext?: Record<string, any>): void {
    this.parent.info(
      message,
      additionalContext ? { ...this.context, ...additionalContext } : this.context
    );
  }

  warn(message: string, additionalContext?: Record<string, any>): void {
    this.parent.warn(
      message,
      additionalContext ? { ...this.context, ...additionalContext } : this.context
    );
  }

  error(message: string, error?: Error, additionalContext?: Record<string, any>): void {
    this.parent.error(
      message,
      error,
      additionalContext ? { ...this.context, ...additionalContext } : this.context
    );
  }
}

// 5. Log Output Interface
interface LogOutput {
  write(entry: LogEntry): void;
}

// 6. Console Output
class ConsoleOutput implements LogOutput {
  write(entry: LogEntry): void {
    const levelName = LogLevel[entry.level];
    const prefix = `[${entry.timestamp.toISOString()}] [${levelName}]`;

    switch (entry.level) {
      case LogLevel.DEBUG:
        console.debug(prefix, entry.message, entry.context || '');
        break;
      case LogLevel.INFO:
        console.info(prefix, entry.message, entry.context || '');
        break;
      case LogLevel.WARN:
        console.warn(prefix, entry.message, entry.context || '');
        break;
      case LogLevel.ERROR:
      case LogLevel.FATAL:
        console.error(prefix, entry.message, entry.error || entry.context || '');
        if (entry.stack) {
          console.error(entry.stack);
        }
        break;
    }
  }
}

// 7. File Output (IndexedDB)
class IndexedDBOutput implements LogOutput {
  private dbName: string = 'logs';
  private storeName: string = 'entries';
  private db: IDBDatabase | null = null;
  private buffer: LogEntry[] = [];
  private bufferSize: number = 100;

  async initialize(): Promise<void> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, 1);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        this.db = request.result;
        resolve();
      };

      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        if (!db.objectStoreNames.contains(this.storeName)) {
          const store = db.createObjectStore(this.storeName, { keyPath: 'id', autoIncrement: true });
          store.createIndex('timestamp', 'timestamp', { unique: false });
          store.createIndex('level', 'level', { unique: false });
        }
      };
    });
  }

  write(entry: LogEntry): void {
    this.buffer.push(entry);

    if (this.buffer.length >= this.bufferSize) {
      this.flush();
    }
  }

  flush(): void {
    if (this.buffer.length === 0 || !this.db) {
      return;
    }

    const transaction = this.db.transaction([this.storeName], 'readwrite');
    const store = transaction.objectStore(this.storeName);

    for (const entry of this.buffer) {
      store.add(entry);
    }

    this.buffer = [];
  }

  // Query logs
  async queryLogs(
    filter: {
      startDate?: Date;
      endDate?: Date;
      minLevel?: LogLevel;
      limit?: number;
    } = {}
  ): Promise<LogEntry[]> {
    if (!this.db) {
      await this.initialize();
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([this.storeName], 'readonly');
      const store = transaction.objectStore(this.storeName);
      const index = store.index('timestamp');

      const range = IDBKeyRange.lowerBound(filter.startDate?.getTime() || 0);
      const request = index.openCursor(range);

      const results: LogEntry[] = [];
      let count = 0;

      request.onsuccess = (event) => {
        const cursor = (event.target as IDBRequest).result;

        if (cursor && (!filter.limit || count < filter.limit)) {
          const entry = cursor.value as LogEntry;

          if (!filter.minLevel || entry.level >= filter.minLevel) {
            if (!filter.endDate || entry.timestamp <= filter.endDate) {
              results.push(entry);
              count++;
            }
          }

          cursor.continue();
        } else {
          resolve(results);
        }
      };

      request.onerror = () => reject(request.error);
    });
  }

  // Clear old logs
  async clearOldLogs(beforeDate: Date): Promise<number> {
    if (!this.db) {
      await this.initialize();
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const index = store.index('timestamp');

      const range = IDBKeyRange.upperBound(beforeDate.getTime());
      const request = index.openCursor(range);

      let count = 0;

      request.onsuccess = (event) => {
        const cursor = (event.target as IDBRequest).result;

        if (cursor) {
          cursor.delete();
          count++;
          cursor.continue();
        } else {
          resolve(count);
        }
      };

      request.onerror = () => reject(request.error);
    });
  }
}

// 8. Remote Output (HTTP)
class RemoteOutput implements LogOutput {
  private endpoint: string;
  private batchSize: number = 10;
  private buffer: LogEntry[] = [];

  constructor(endpoint: string) {
    this.endpoint = endpoint;
  }

  write(entry: LogEntry): void {
    this.buffer.push(entry);

    if (this.buffer.length >= this.batchSize) {
      this.flush();
    }
  }

  async flush(): Promise<void> {
    if (this.buffer.length === 0) {
      return;
    }

    const entries = [...this.buffer];
    this.buffer = [];

    try {
      const response = await fetch(this.endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(entries)
      });

      if (!response.ok) {
        console.error('Failed to send logs to remote endpoint');
      }
    } catch (error) {
      console.error('Error sending logs to remote endpoint:', error);
    }
  }
}

// 9. Formatted Output
class FormattedOutput implements LogOutput {
  constructor(
    private output: LogOutput,
    private formatter: (entry: LogEntry) => string
  ) {}

  write(entry: LogEntry): void {
    const formatted = this.formatter(entry);
    const formattedEntry: LogEntry = {
      ...entry,
      message: formatted
    };
    this.output.write(formattedEntry);
  }
}

// 10. Logger Factory
class LoggerFactory {
  private static instance: Logger;

  static getLogger(): Logger {
    if (!this.instance) {
      this.instance = new Logger();

      // Add default outputs
      this.instance.addOutput(new ConsoleOutput());
    }

    return this.instance;
  }

  static createLogger(name: string): ChildLogger {
    return this.getLogger().child({ logger: name });
  }
}

// Usage Examples
async function demonstrateLogRecording() {
  console.log('=== Web TypeScript Log Recording Examples ===\n');

  const logger = LoggerFactory.getLogger();
  const consoleOutput = new ConsoleOutput();

  // 1. Basic logging
  console.log('--- 1. Basic Logging ---');
  logger.debug('Debug message');
  logger.info('Info message');
  logger.warn('Warning message');
  logger.error('Error message');

  // 2. Logging with context
  console.log('\n--- 2. Logging with Context ---');
  logger.info('User logged in', { userId: '123', ip: '192.168.1.1' });
  logger.warn('High memory usage', { used: 512, total: 1024, unit: 'MB' });

  // 3. Child logger
  console.log('\n--- 3. Child Logger ---');
  const userLogger = logger.child({ component: 'UserService' });
  userLogger.info('Creating user', { username: 'testuser' });
  userLogger.error('User creation failed', new Error('Duplicate email'));

  // 4. IndexedDB output
  console.log('\n--- 4. IndexedDB Output ---');
  const indexedDBOutput = new IndexedDBOutput();
  await indexedDBOutput.initialize();
  logger.addOutput(indexedDBOutput);

  logger.info('This will be saved to IndexedDB');
  logger.warn('This too');

  await indexedDBOutput.flush();

  const logs = await indexedDBOutput.queryLogs({ limit: 10 });
  console.log(`Retrieved ${logs.length} logs from IndexedDB`);

  // 5. Formatted output
  console.log('\n--- 5. Formatted Output ---');
  const jsonOutput = new FormattedOutput(consoleOutput, (entry) => {
    return JSON.stringify({
      timestamp: entry.timestamp,
      level: LogLevel[entry.level],
      message: entry.message,
      context: entry.context
    });
  });

  logger.info('Formatted log entry', { data: 'test' });

  // 6. Remote output (simulated)
  console.log('\n--- 6. Remote Output ---');
  // const remoteOutput = new RemoteOutput('https://api.example.com/logs');
  // logger.addOutput(remoteOutput);

  console.log('\n=== All Log Recording Examples Completed ===');
}

// Export functions
export { LogLevel, Logger, ChildLogger, LogOutput, ConsoleOutput, IndexedDBOutput, RemoteOutput, FormattedOutput, LoggerFactory };
export { demonstrateLogRecording };
export type { LogEntry };

💻 Валидация Параметров typescript

🟡 intermediate ⭐⭐⭐

Валидация параметров функции с проверкой типов, проверкой диапазона и кастомными правилами

⏱️ 25 min 🏷️ typescript, web, error handling, validation
Prerequisites: Intermediate TypeScript, Decorators
// Web TypeScript Parameter Validation Examples
// Comprehensive parameter validation system

// 1. Validation Result
interface ValidationResult {
  isValid: boolean;
  errors: string[];
}

// 2. Basic Validators
class Validators {
  // Required validator
  static required(value: any): ValidationResult {
    if (value === null || value === undefined || value === '') {
      return {
        isValid: false,
        errors: ['Value is required']
      };
    }
    return { isValid: true, errors: [] };
  }

  // Type validator
  static type(value: any, expectedType: string): ValidationResult {
    const actualType = typeof value;

    if (actualType !== expectedType) {
      return {
        isValid: false,
        errors: [`Expected type '${expectedType}', got '${actualType}'`]
      };
    }

    return { isValid: true, errors: [] };
  }

  // Number range validator
  static range(value: number, min: number, max: number): ValidationResult {
    const errors: string[] = [];

    if (value < min) {
      errors.push(`Value ${value} is less than minimum ${min}`);
    }

    if (value > max) {
      errors.push(`Value ${value} is greater than maximum ${max}`);
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }

  // String length validator
  static length(value: string, min: number, max: number): ValidationResult {
    const actualLength = value.length;
    const errors: string[] = [];

    if (actualLength < min) {
      errors.push(`Length ${actualLength} is less than minimum ${min}`);
    }

    if (actualLength > max) {
      errors.push(`Length ${actualLength} is greater than maximum ${max}`);
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }

  // Pattern validator
  static pattern(value: string, regex: RegExp, description?: string): ValidationResult {
    if (!regex.test(value)) {
      return {
        isValid: false,
        errors: [description || `Value does not match pattern ${regex}`]
      };
    }

    return { isValid: true, errors: [] };
  }

  // Email validator
  static email(value: string): ValidationResult {
    const emailRegex = /^[^[\s@]]+@[^\s@]+\.[^\s@]+$/;
    return this.pattern(value, emailRegex, 'Invalid email format');
  }

  // URL validator
  static url(value: string): ValidationResult {
    try {
      new URL(value);
      return { isValid: true, errors: [] };
    } catch {
      return {
        isValid: false,
        errors: ['Invalid URL format']
      };
    }
  }

  // Array validator
  static array(value: any, itemValidator?: (item: any, index: number) => ValidationResult): ValidationResult {
    if (!Array.isArray(value)) {
      return {
        isValid: false,
        errors: ['Value is not an array']
      };
    }

    if (itemValidator) {
      const errors: string[] = [];

      for (let i = 0; i < value.length; i++) {
        const result = itemValidator(value[i], i);
        if (!result.isValid) {
          errors.push(`Index ${i}: ${result.errors.join(', ')}`);
        }
      }

      return {
        isValid: errors.length === 0,
        errors
      };
    }

    return { isValid: true, errors: [] };
  }
}

// 3. Validation Schema
class ValidationSchema {
  private rules: Map<string, Array<(value: any) => ValidationResult>> = new Map();

  // Add rule for field
  addRule(field: string, validator: (value: any) => ValidationResult): this {
    if (!this.rules.has(field)) {
      this.rules.set(field, []);
    }
    this.rules.get(field)!.push(validator);
    return this;
  }

  // Validate object
  validate(obj: any): ValidationResult {
    const allErrors: string[] = [];

    for (const [field, validators] of this.rules) {
      const value = obj[field];

      for (const validator of validators) {
        const result = validator(value);

        if (!result.isValid) {
          allErrors.push(...result.errors.map(err => `${field}: ${err}`));
        }
      }
    }

    return {
      isValid: allErrors.length === 0,
      errors: allErrors
    };
  }

  // Create schema from config
  static fromConfig(config: Record<string, string[]>): ValidationSchema {
    const schema = new ValidationSchema();

    for (const [field, rules] of Object.entries(config)) {
      for (const rule of rules) {
        const validator = Validators.createValidator(rule);
        if (validator) {
          schema.addRule(field, validator);
        }
      }
    }

    return schema;
  }
}

// 4. Validator Factory
namespace Validators {
  // Create validator from string
  export function createValidator(rule: string): ((value: any) => ValidationResult) | null {
    const parts = rule.split(':');
    const name = parts[0];
    const args = parts.slice(1);

    switch (name) {
      case 'required':
        return (value) => Validators.required(value);
      case 'type':
        return (value) => Validators.type(value, args[0]);
      case 'range':
        return (value) => Validators.range(value, Number(args[0]), Number(args[1]));
      case 'length':
        return (value) => Validators.length(value, Number(args[0]), Number(args[1]));
      case 'email':
        return (value) => Validators.email(value);
      case 'url':
        return (value) => Validators.url(value);
      case 'pattern':
        return (value) => Validators.pattern(value, new RegExp(args[0]));
      default:
        return null;
    }
  }
}

// 5. Function Argument Decorator
function validateArgs(...validators: Array<(value: any) => ValidationResult>) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
      for (let i = 0; i < validators.length; i++) {
        if (validators[i]) {
          const result = validators[i](args[i]);

          if (!result.isValid) {
            throw new ValidationError(
              `Invalid argument ${i} for '${propertyKey}': ${result.errors.join(', ')}`,
              { argument: i, errors: result.errors }
            );
          }
        }
      }

      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
}

// 6. Schema Validator Decorator
function validateSchema(schema: ValidationSchema) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
      if (args.length > 0 && typeof args[0] === 'object') {
        const result = schema.validate(args[0]);

        if (!result.isValid) {
          throw new ValidationError(
            `Validation failed for '${propertyKey}': ${result.errors.join(', ')}`,
            { errors: result.errors }
          );
        }
      }

      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
}

// 7. Object Validator
class ObjectValidator {
  // Validate nested object
  static validate(
    obj: any,
    schema: Record<string, Array<(value: any) => ValidationResult>>
  ): ValidationResult {
    const allErrors: string[] = [];

    for (const [field, validators] of Object.entries(schema)) {
      const value = obj[field];

      for (const validator of validators) {
        const result = validator(value);

        if (!result.isValid) {
          allErrors.push(...result.errors.map(err => `${field}: ${err}`));
        }
      }
    }

    return {
      isValid: allErrors.length === 0,
      errors: allErrors
    };
  }

  // Validate partial object
  static validatePartial(
    obj: any,
    schema: Record<string, Array<(value: any) => ValidationResult>>
  ): ValidationResult {
    const allErrors: string[] = [];

    for (const [field, validators] of Object.entries(schema)) {
      if (!(field in obj)) {
        continue;
      }

      const value = obj[field];

      for (const validator of validators) {
        const result = validator(value);

        if (!result.isValid) {
          allErrors.push(...result.errors.map(err => `${field}: ${err}`));
        }
      }
    }

    return {
      isValid: allErrors.length === 0,
      errors: allErrors
    };
  }
}

// 8. Async Validator
class AsyncValidator {
  // Validate async
  static async validate(
    value: any,
    validators: Array<(value: any) => Promise<ValidationResult>>
  ): Promise<ValidationResult> {
    const errors: string[] = [];

    for (const validator of validators) {
      const result = await validator(value);

      if (!result.isValid) {
        errors.push(...result.errors);
      }
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }

  // Check uniqueness async
  static async unique(
    value: any,
    checker: (value: any) => Promise<boolean>
  ): Promise<ValidationResult> {
    const isUnique = await checker(value);

    if (!isUnique) {
      return {
        isValid: false,
        errors: ['Value must be unique']
      };
    }

    return { isValid: true, errors: [] };
  }
}

// 9. Validation Middleware
class ValidationMiddleware {
  // Validate request data
  static validate(schema: ValidationSchema) {
    return async (data: any): Promise<void> => {
      const result = schema.validate(data);

      if (!result.isValid) {
        throw new ValidationError('Validation failed', {
          errors: result.errors
        });
      }
    };
  }
}

// Usage Examples
async function demonstrateParameterValidation() {
  console.log('=== Web TypeScript Parameter Validation Examples ===\n');

  // 1. Basic validators
  console.log('--- 1. Basic Validators ---');
  console.log('Required:', Validators.required('test'));
  console.log('Type:', Validators.type(123, 'number'));
  console.log('Range:', Validators.range(50, 0, 100));
  console.log('Email:', Validators.email('[email protected]'));

  // 2. Schema validation
  console.log('\n--- 2. Schema Validation ---');
  const userSchema = new ValidationSchema()
    .addRule('name', v => Validators.required(v))
    .addRule('name', v => Validators.length(v as string, 2, 50))
    .addRule('age', v => Validators.type(v, 'number'))
    .addRule('age', v => Validators.range(v as number, 0, 150))
    .addRule('email', v => Validators.email(v as string));

  const user1 = { name: 'John Doe', age: 30, email: '[email protected]' };
  const result1 = userSchema.validate(user1);
  console.log('Valid user:', result1);

  const user2 = { name: 'X', age: 200, email: 'invalid' };
  const result2 = userSchema.validate(user2);
  console.log('Invalid user:', result2);

  // 3. Object validation
  console.log('\n--- 3. Object Validation ---');
  const productSchema = {
    name: [v => Validators.required(v), v => Validators.length(v as string, 1, 100)],
    price: [v => Validators.type(v, 'number'), v => Validators.range(v as number, 0, Infinity)],
    url: [v => Validators.url(v as string)]
  };

  const product = { name: 'Widget', price: 29.99, url: 'https://example.com' };
  const productResult = ObjectValidator.validate(product, productSchema);
  console.log('Product validation:', productResult);

  // 4. Array validation
  console.log('\n--- 4. Array Validation ---');
  const arrayResult = Validators.array(
    [1, 2, 3, 4, 5],
    (item, index) => Validators.range(item as number, 0, 10)
  );
  console.log('Array validation:', arrayResult);

  console.log('\n=== All Parameter Validation Examples Completed ===');
}

// Custom Error import
class ValidationError extends Error {
  constructor(
    message: string,
    public code: string = 'VALIDATION_ERROR',
    public details?: any
  ) {
    super(message);
    this.name = 'ValidationError';
  }
}

// Export functions
export { Validators, ValidationSchema, ObjectValidator, AsyncValidator, ValidationMiddleware, validateArgs, validateSchema };
export { demonstrateParameterValidation };
export type { ValidationResult };