🎯 empfohlene Sammlungen
Balanced sample collections from various categories for you to explore
Web TypeScript Fehlerbehandlungsbeispiele
Web TypeScript Fehlerbehandlungsbeispiele einschließlich Ausnahmenabfang, Protokollierung und Parametervalidierung
💻 Ausnahmenabfang typescript
🟢 simple
⭐⭐⭐
Try-Catch-Ausnahmen behandeln, benutzerdefinierte Fehlerklassen und Fehlerweitergabe
⏱️ 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 };
💻 Protokollierung typescript
🟡 intermediate
⭐⭐⭐
Protokollierungssysteme mit mehreren Ebenen, Ausgaben und Formatierern implementieren
⏱️ 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 };
💻 Parametervalidierung typescript
🟡 intermediate
⭐⭐⭐
Funktionsparameter mit Typprüfung, Bereichvalidierung und benutzerdefinierten Regeln validieren
⏱️ 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 };