🎯 Ejemplos recomendados
Balanced sample collections from various categories for you to explore
Ejemplos de Manejo de Errores Web TypeScript
Ejemplos de manejo de errores Web TypeScript incluyendo captura de excepciones, registro de registros y validación de parámetros
💻 Captura de Excepciones typescript
🟢 simple
⭐⭐⭐
Manejar excepciones try-catch, clases de error personalizadas y propagación de errores
⏱️ 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 };
💻 Registro de Logs typescript
🟡 intermediate
⭐⭐⭐
Implementar sistemas de registro con múltiples niveles, salidas y formateadores
⏱️ 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 };
💻 Validación de Parámetros typescript
🟡 intermediate
⭐⭐⭐
Validar parámetros de función con verificación de tipos, validación de rango y reglas personalizadas
⏱️ 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 };