7.1 错误处理基础

7.1.1 JavaScript 错误类型

TypeScript 继承了 JavaScript 的错误处理机制,了解不同类型的错误对于有效的错误处理至关重要:

// 内置错误类型
class ErrorTypes {
    static demonstrateErrors() {
        try {
            // SyntaxError - 语法错误(通常在编译时捕获)
            // eval('const x = ;'); // 这会抛出 SyntaxError
            
            // ReferenceError - 引用错误
            // console.log(undefinedVariable); // ReferenceError
            
            // TypeError - 类型错误
            const nullValue: any = null;
            nullValue.someMethod(); // TypeError: Cannot read property 'someMethod' of null
            
        } catch (error) {
            if (error instanceof TypeError) {
                console.error('Type Error:', error.message);
            } else if (error instanceof ReferenceError) {
                console.error('Reference Error:', error.message);
            } else {
                console.error('Unknown Error:', error);
            }
        }
        
        try {
            // RangeError - 范围错误
            const arr = new Array(-1); // RangeError: Invalid array length
        } catch (error) {
            console.error('Range Error:', error.message);
        }
        
        try {
            // URIError - URI 错误
            decodeURIComponent('%'); // URIError: URI malformed
        } catch (error) {
            console.error('URI Error:', error.message);
        }
    }
}

// 自定义错误类型
class CustomError extends Error {
    constructor(
        message: string,
        public code: string,
        public statusCode?: number
    ) {
        super(message);
        this.name = 'CustomError';
        
        // 确保堆栈跟踪正确指向这个构造函数
        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, CustomError);
        }
    }
}

class ValidationError extends CustomError {
    constructor(
        message: string,
        public field: string,
        public value: any
    ) {
        super(message, 'VALIDATION_ERROR', 400);
        this.name = 'ValidationError';
    }
}

class NetworkError extends CustomError {
    constructor(
        message: string,
        public url: string,
        statusCode?: number
    ) {
        super(message, 'NETWORK_ERROR', statusCode);
        this.name = 'NetworkError';
    }
}

class BusinessLogicError extends CustomError {
    constructor(
        message: string,
        public operation: string,
        public context?: Record<string, any>
    ) {
        super(message, 'BUSINESS_LOGIC_ERROR', 422);
        this.name = 'BusinessLogicError';
    }
}

7.1.2 错误处理策略

// 错误处理策略枚举
enum ErrorHandlingStrategy {
    THROW = 'throw',
    LOG = 'log',
    IGNORE = 'ignore',
    RETRY = 'retry',
    FALLBACK = 'fallback'
}

// 错误处理配置
interface ErrorHandlingConfig {
    strategy: ErrorHandlingStrategy;
    maxRetries?: number;
    retryDelay?: number;
    fallbackValue?: any;
    logger?: (error: Error) => void;
}

// 通用错误处理器
class ErrorHandler {
    private static defaultConfig: ErrorHandlingConfig = {
        strategy: ErrorHandlingStrategy.THROW,
        maxRetries: 3,
        retryDelay: 1000,
        logger: console.error
    };
    
    static async handle<T>(
        operation: () => Promise<T>,
        config: Partial<ErrorHandlingConfig> = {}
    ): Promise<T | undefined> {
        const finalConfig = { ...this.defaultConfig, ...config };
        let lastError: Error;
        
        for (let attempt = 1; attempt <= (finalConfig.maxRetries || 1); attempt++) {
            try {
                return await operation();
            } catch (error) {
                lastError = error as Error;
                
                if (finalConfig.logger) {
                    finalConfig.logger(error as Error);
                }
                
                if (attempt < (finalConfig.maxRetries || 1) && 
                    finalConfig.strategy === ErrorHandlingStrategy.RETRY) {
                    await this.delay(finalConfig.retryDelay || 1000);
                    continue;
                }
                
                break;
            }
        }
        
        // 处理最终错误
        switch (finalConfig.strategy) {
            case ErrorHandlingStrategy.THROW:
                throw lastError!;
            case ErrorHandlingStrategy.LOG:
                if (finalConfig.logger) {
                    finalConfig.logger(lastError!);
                }
                return undefined;
            case ErrorHandlingStrategy.IGNORE:
                return undefined;
            case ErrorHandlingStrategy.FALLBACK:
                return finalConfig.fallbackValue;
            default:
                throw lastError!;
        }
    }
    
    private static delay(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

// 使用示例
async function demonstrateErrorHandling() {
    // 重试策略
    const result1 = await ErrorHandler.handle(
        async () => {
            if (Math.random() > 0.7) {
                throw new NetworkError('Network timeout', 'https://api.example.com');
            }
            return 'Success!';
        },
        {
            strategy: ErrorHandlingStrategy.RETRY,
            maxRetries: 3,
            retryDelay: 1000
        }
    );
    
    // 回退策略
    const result2 = await ErrorHandler.handle(
        async () => {
            throw new Error('Always fails');
        },
        {
            strategy: ErrorHandlingStrategy.FALLBACK,
            fallbackValue: 'Default value'
        }
    );
    
    console.log('Results:', { result1, result2 });
}

7.2 类型安全的错误处理

7.2.1 Result 模式

// Result 类型定义
type Result<T, E = Error> = Success<T> | Failure<E>;

class Success<T> {
    readonly isSuccess = true;
    readonly isFailure = false;
    
    constructor(public readonly value: T) {}
    
    map<U>(fn: (value: T) => U): Result<U, never> {
        return new Success(fn(this.value));
    }
    
    flatMap<U, E>(fn: (value: T) => Result<U, E>): Result<U, E> {
        return fn(this.value);
    }
    
    mapError<F>(_fn: (error: never) => F): Result<T, F> {
        return this as any;
    }
    
    unwrap(): T {
        return this.value;
    }
    
    unwrapOr(_defaultValue: T): T {
        return this.value;
    }
}

class Failure<E> {
    readonly isSuccess = false;
    readonly isFailure = true;
    
    constructor(public readonly error: E) {}
    
    map<U>(_fn: (value: never) => U): Result<U, E> {
        return this as any;
    }
    
    flatMap<U, F>(_fn: (value: never) => Result<U, F>): Result<U, E> {
        return this as any;
    }
    
    mapError<F>(fn: (error: E) => F): Result<never, F> {
        return new Failure(fn(this.error));
    }
    
    unwrap(): never {
        throw this.error;
    }
    
    unwrapOr<T>(defaultValue: T): T {
        return defaultValue;
    }
}

// Result 工厂函数
class ResultFactory {
    static success<T>(value: T): Result<T, never> {
        return new Success(value);
    }
    
    static failure<E>(error: E): Result<never, E> {
        return new Failure(error);
    }
    
    static fromThrowable<T, E = Error>(
        fn: () => T,
        errorMapper?: (error: unknown) => E
    ): Result<T, E> {
        try {
            return new Success(fn());
        } catch (error) {
            const mappedError = errorMapper ? errorMapper(error) : error as E;
            return new Failure(mappedError);
        }
    }
    
    static async fromAsyncThrowable<T, E = Error>(
        fn: () => Promise<T>,
        errorMapper?: (error: unknown) => E
    ): Promise<Result<T, E>> {
        try {
            const value = await fn();
            return new Success(value);
        } catch (error) {
            const mappedError = errorMapper ? errorMapper(error) : error as E;
            return new Failure(mappedError);
        }
    }
}

// 使用 Result 模式
interface User {
    id: string;
    name: string;
    email: string;
}

class UserService {
    async getUser(id: string): Promise<Result<User, ValidationError | NetworkError>> {
        // 验证输入
        if (!id || id.trim() === '') {
            return ResultFactory.failure(
                new ValidationError('User ID is required', 'id', id)
            );
        }
        
        // 模拟网络请求
        return ResultFactory.fromAsyncThrowable(
            async () => {
                if (Math.random() > 0.8) {
                    throw new Error('Network timeout');
                }
                
                return {
                    id,
                    name: 'Alice',
                    email: 'alice@example.com'
                };
            },
            (error) => new NetworkError(
                error instanceof Error ? error.message : 'Unknown network error',
                `/api/users/${id}`
            )
        );
    }
    
    async updateUser(
        id: string, 
        updates: Partial<User>
    ): Promise<Result<User, ValidationError | NetworkError | BusinessLogicError>> {
        // 获取用户
        const userResult = await this.getUser(id);
        if (userResult.isFailure) {
            return userResult;
        }
        
        const user = userResult.value;
        
        // 业务逻辑验证
        if (updates.email && !this.isValidEmail(updates.email)) {
            return ResultFactory.failure(
                new ValidationError('Invalid email format', 'email', updates.email)
            );
        }
        
        // 模拟更新操作
        return ResultFactory.fromAsyncThrowable(
            async () => {
                if (Math.random() > 0.9) {
                    throw new Error('Database error');
                }
                
                return { ...user, ...updates };
            },
            (error) => new BusinessLogicError(
                error instanceof Error ? error.message : 'Update failed',
                'updateUser',
                { id, updates }
            )
        );
    }
    
    private isValidEmail(email: string): boolean {
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return emailRegex.test(email);
    }
}

// 使用示例
async function demonstrateResultPattern() {
    const userService = new UserService();
    
    // 链式操作
    const result = await userService.getUser('123')
        .then(userResult => 
            userResult.flatMap(user => 
                userService.updateUser(user.id, { name: 'Bob' })
            )
        );
    
    if (result.isSuccess) {
        console.log('Updated user:', result.value);
    } else {
        console.error('Operation failed:', result.error);
        
        // 类型安全的错误处理
        if (result.error instanceof ValidationError) {
            console.error(`Validation error in field ${result.error.field}:`, result.error.message);
        } else if (result.error instanceof NetworkError) {
            console.error(`Network error for ${result.error.url}:`, result.error.message);
        } else if (result.error instanceof BusinessLogicError) {
            console.error(`Business logic error in ${result.error.operation}:`, result.error.message);
        }
    }
}

7.2.2 Option 模式

// Option 类型定义
type Option<T> = Some<T> | None;

class Some<T> {
    readonly isSome = true;
    readonly isNone = false;
    
    constructor(public readonly value: T) {}
    
    map<U>(fn: (value: T) => U): Option<U> {
        return new Some(fn(this.value));
    }
    
    flatMap<U>(fn: (value: T) => Option<U>): Option<U> {
        return fn(this.value);
    }
    
    filter(predicate: (value: T) => boolean): Option<T> {
        return predicate(this.value) ? this : new None();
    }
    
    unwrap(): T {
        return this.value;
    }
    
    unwrapOr(_defaultValue: T): T {
        return this.value;
    }
    
    unwrapOrElse(_fn: () => T): T {
        return this.value;
    }
}

class None {
    readonly isSome = false;
    readonly isNone = true;
    
    map<U>(_fn: (value: never) => U): Option<U> {
        return this as any;
    }
    
    flatMap<U>(_fn: (value: never) => Option<U>): Option<U> {
        return this as any;
    }
    
    filter(_predicate: (value: never) => boolean): Option<never> {
        return this as any;
    }
    
    unwrap(): never {
        throw new Error('Called unwrap on None');
    }
    
    unwrapOr<T>(defaultValue: T): T {
        return defaultValue;
    }
    
    unwrapOrElse<T>(fn: () => T): T {
        return fn();
    }
}

// Option 工厂函数
class OptionFactory {
    static some<T>(value: T): Option<T> {
        return new Some(value);
    }
    
    static none<T = never>(): Option<T> {
        return new None();
    }
    
    static fromNullable<T>(value: T | null | undefined): Option<T> {
        return value != null ? new Some(value) : new None();
    }
    
    static fromPredicate<T>(value: T, predicate: (value: T) => boolean): Option<T> {
        return predicate(value) ? new Some(value) : new None();
    }
}

// 使用 Option 模式
class ConfigService {
    private config: Record<string, any> = {
        apiUrl: 'https://api.example.com',
        timeout: 5000,
        retries: 3
    };
    
    get<T>(key: string): Option<T> {
        return OptionFactory.fromNullable(this.config[key]);
    }
    
    getApiUrl(): Option<string> {
        return this.get<string>('apiUrl')
            .filter(url => url.startsWith('https://'));
    }
    
    getTimeout(): number {
        return this.get<number>('timeout')
            .filter(timeout => timeout > 0)
            .unwrapOr(5000);
    }
    
    getRetries(): number {
        return this.get<number>('retries')
            .filter(retries => retries >= 0 && retries <= 10)
            .unwrapOr(3);
    }
}

// 链式操作示例
function demonstrateOptionChaining() {
    const configService = new ConfigService();
    
    // 安全的链式操作
    const result = configService.getApiUrl()
        .map(url => `${url}/users`)
        .map(url => new URL(url))
        .filter(url => url.protocol === 'https:')
        .map(url => url.toString());
    
    if (result.isSome) {
        console.log('API endpoint:', result.value);
    } else {
        console.log('Invalid or missing API URL');
    }
    
    // 使用 flatMap 进行复杂操作
    const userEndpoint = configService.getApiUrl()
        .flatMap(baseUrl => {
            try {
                const url = new URL('/users', baseUrl);
                return OptionFactory.some(url.toString());
            } catch {
                return OptionFactory.none();
            }
        });
    
    console.log('User endpoint:', userEndpoint.unwrapOr('Not available'));
}

7.3 调试技巧

7.3.1 调试工具和技术

// 调试装饰器
function debug(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    
    descriptor.value = function (...args: any[]) {
        console.group(`🐛 Debug: ${target.constructor.name}.${propertyKey}`);
        console.log('Arguments:', args);
        console.time('Execution time');
        
        try {
            const result = originalMethod.apply(this, args);
            
            if (result instanceof Promise) {
                return result
                    .then(value => {
                        console.log('Async result:', value);
                        console.timeEnd('Execution time');
                        console.groupEnd();
                        return value;
                    })
                    .catch(error => {
                        console.error('Async error:', error);
                        console.timeEnd('Execution time');
                        console.groupEnd();
                        throw error;
                    });
            } else {
                console.log('Result:', result);
                console.timeEnd('Execution time');
                console.groupEnd();
                return result;
            }
        } catch (error) {
            console.error('Error:', error);
            console.timeEnd('Execution time');
            console.groupEnd();
            throw error;
        }
    };
    
    return descriptor;
}

// 性能监控装饰器
function performance(threshold: number = 100) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        const originalMethod = descriptor.value;
        
        descriptor.value = function (...args: any[]) {
            const start = performance.now();
            
            const result = originalMethod.apply(this, args);
            
            if (result instanceof Promise) {
                return result.finally(() => {
                    const duration = performance.now() - start;
                    if (duration > threshold) {
                        console.warn(
                            `⚠️ Slow operation: ${target.constructor.name}.${propertyKey} took ${duration.toFixed(2)}ms`
                        );
                    }
                });
            } else {
                const duration = performance.now() - start;
                if (duration > threshold) {
                    console.warn(
                        `⚠️ Slow operation: ${target.constructor.name}.${propertyKey} took ${duration.toFixed(2)}ms`
                    );
                }
                return result;
            }
        };
        
        return descriptor;
    };
}

// 调试工具类
class DebugUtils {
    private static isDebugMode = process.env.NODE_ENV === 'development';
    
    static log(message: string, ...args: any[]): void {
        if (this.isDebugMode) {
            console.log(`[DEBUG] ${message}`, ...args);
        }
    }
    
    static trace(message: string): void {
        if (this.isDebugMode) {
            console.trace(`[TRACE] ${message}`);
        }
    }
    
    static assert(condition: boolean, message: string): void {
        if (this.isDebugMode && !condition) {
            console.assert(condition, message);
        }
    }
    
    static time(label: string): void {
        if (this.isDebugMode) {
            console.time(label);
        }
    }
    
    static timeEnd(label: string): void {
        if (this.isDebugMode) {
            console.timeEnd(label);
        }
    }
    
    static profile(label: string): void {
        if (this.isDebugMode && console.profile) {
            console.profile(label);
        }
    }
    
    static profileEnd(label: string): void {
        if (this.isDebugMode && console.profileEnd) {
            console.profileEnd(label);
        }
    }
    
    static memory(): void {
        if (this.isDebugMode && (performance as any).memory) {
            const memory = (performance as any).memory;
            console.table({
                'Used JS Heap Size': `${(memory.usedJSHeapSize / 1024 / 1024).toFixed(2)} MB`,
                'Total JS Heap Size': `${(memory.totalJSHeapSize / 1024 / 1024).toFixed(2)} MB`,
                'JS Heap Size Limit': `${(memory.jsHeapSizeLimit / 1024 / 1024).toFixed(2)} MB`
            });
        }
    }
}

// 使用示例
class DataProcessor {
    @debug
    @performance(50)
    async processData(data: any[]): Promise<any[]> {
        DebugUtils.log('Starting data processing', { count: data.length });
        DebugUtils.time('Data processing');
        
        const result = [];
        
        for (let i = 0; i < data.length; i++) {
            DebugUtils.assert(data[i] != null, `Data item at index ${i} is null`);
            
            // 模拟处理
            await new Promise(resolve => setTimeout(resolve, 10));
            result.push({ ...data[i], processed: true });
            
            if (i % 100 === 0) {
                DebugUtils.log(`Processed ${i + 1}/${data.length} items`);
                DebugUtils.memory();
            }
        }
        
        DebugUtils.timeEnd('Data processing');
        return result;
    }
}

7.3.2 错误边界和全局错误处理

// 全局错误处理器
class GlobalErrorHandler {
    private static instance: GlobalErrorHandler;
    private errorListeners: Array<(error: Error, context?: any) => void> = [];
    private unhandledRejectionListeners: Array<(reason: any, promise: Promise<any>) => void> = [];
    
    private constructor() {
        this.setupGlobalHandlers();
    }
    
    static getInstance(): GlobalErrorHandler {
        if (!this.instance) {
            this.instance = new GlobalErrorHandler();
        }
        return this.instance;
    }
    
    private setupGlobalHandlers(): void {
        // 处理未捕获的错误
        window.addEventListener('error', (event) => {
            this.handleError(new Error(event.message), {
                filename: event.filename,
                lineno: event.lineno,
                colno: event.colno,
                stack: event.error?.stack
            });
        });
        
        // 处理未捕获的 Promise 拒绝
        window.addEventListener('unhandledrejection', (event) => {
            this.handleUnhandledRejection(event.reason, event.promise);
            event.preventDefault(); // 阻止默认的控制台错误输出
        });
    }
    
    addErrorListener(listener: (error: Error, context?: any) => void): void {
        this.errorListeners.push(listener);
    }
    
    addUnhandledRejectionListener(
        listener: (reason: any, promise: Promise<any>) => void
    ): void {
        this.unhandledRejectionListeners.push(listener);
    }
    
    private handleError(error: Error, context?: any): void {
        console.error('Global error caught:', error, context);
        
        this.errorListeners.forEach(listener => {
            try {
                listener(error, context);
            } catch (listenerError) {
                console.error('Error in error listener:', listenerError);
            }
        });
    }
    
    private handleUnhandledRejection(reason: any, promise: Promise<any>): void {
        console.error('Unhandled promise rejection:', reason, promise);
        
        this.unhandledRejectionListeners.forEach(listener => {
            try {
                listener(reason, promise);
            } catch (listenerError) {
                console.error('Error in unhandled rejection listener:', listenerError);
            }
        });
    }
    
    // 手动报告错误
    reportError(error: Error, context?: any): void {
        this.handleError(error, context);
    }
}

// 错误报告服务
class ErrorReportingService {
    private static readonly MAX_REPORTS_PER_MINUTE = 10;
    private reportCount = 0;
    private lastResetTime = Date.now();
    
    constructor(private apiEndpoint: string) {
        this.setupGlobalErrorHandling();
    }
    
    private setupGlobalErrorHandling(): void {
        const globalHandler = GlobalErrorHandler.getInstance();
        
        globalHandler.addErrorListener((error, context) => {
            this.reportError({
                type: 'javascript_error',
                message: error.message,
                stack: error.stack,
                context,
                timestamp: new Date().toISOString(),
                userAgent: navigator.userAgent,
                url: window.location.href
            });
        });
        
        globalHandler.addUnhandledRejectionListener((reason, promise) => {
            this.reportError({
                type: 'unhandled_rejection',
                message: reason instanceof Error ? reason.message : String(reason),
                stack: reason instanceof Error ? reason.stack : undefined,
                context: { promise: promise.toString() },
                timestamp: new Date().toISOString(),
                userAgent: navigator.userAgent,
                url: window.location.href
            });
        });
    }
    
    private async reportError(errorData: any): Promise<void> {
        // 限流检查
        if (!this.shouldReport()) {
            return;
        }
        
        try {
            await fetch(this.apiEndpoint, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(errorData)
            });
            
            console.log('Error reported successfully');
        } catch (reportingError) {
            console.error('Failed to report error:', reportingError);
        }
    }
    
    private shouldReport(): boolean {
        const now = Date.now();
        
        // 重置计数器(每分钟)
        if (now - this.lastResetTime > 60000) {
            this.reportCount = 0;
            this.lastResetTime = now;
        }
        
        // 检查是否超过限制
        if (this.reportCount >= ErrorReportingService.MAX_REPORTS_PER_MINUTE) {
            return false;
        }
        
        this.reportCount++;
        return true;
    }
}

// 错误边界组件(React 风格)
class ErrorBoundary {
    private errorHandler: (error: Error, errorInfo: any) => void;
    
    constructor(errorHandler: (error: Error, errorInfo: any) => void) {
        this.errorHandler = errorHandler;
    }
    
    wrap<T extends (...args: any[]) => any>(fn: T): T {
        return ((...args: any[]) => {
            try {
                const result = fn(...args);
                
                if (result instanceof Promise) {
                    return result.catch(error => {
                        this.errorHandler(error, {
                            function: fn.name,
                            arguments: args
                        });
                        throw error;
                    });
                }
                
                return result;
            } catch (error) {
                this.errorHandler(error as Error, {
                    function: fn.name,
                    arguments: args
                });
                throw error;
            }
        }) as T;
    }
}

// 使用示例
const errorReporting = new ErrorReportingService('/api/errors');

const errorBoundary = new ErrorBoundary((error, errorInfo) => {
    console.error('Error caught by boundary:', error, errorInfo);
    
    // 可以在这里添加用户通知、错误恢复等逻辑
    showUserNotification('An error occurred. Please try again.');
});

// 包装可能出错的函数
const safeAsyncFunction = errorBoundary.wrap(async (data: any) => {
    // 可能抛出错误的异步操作
    if (!data) {
        throw new ValidationError('Data is required', 'data', data);
    }
    
    return await processData(data);
});

function showUserNotification(message: string): void {
    console.log('User notification:', message);
}

async function processData(data: any): Promise<any> {
    // 模拟数据处理
    return { processed: true, data };
}

7.3.3 源码映射和调试配置

// tsconfig.json 调试配置示例
/*
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "sourceMap": true,           // 生成源码映射
    "inlineSourceMap": false,    // 不内联源码映射
    "inlineSources": false,      // 不内联源码
    "declaration": true,         // 生成声明文件
    "declarationMap": true,      // 生成声明文件的源码映射
    "removeComments": false,     // 保留注释用于调试
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
*/

// 调试辅助工具
class DebugBreakpoints {
    private static breakpoints = new Map<string, boolean>();
    
    static setBreakpoint(id: string, condition: () => boolean = () => true): void {
        this.breakpoints.set(id, true);
        
        if (condition()) {
            console.log(`🔴 Breakpoint hit: ${id}`);
            debugger; // 触发调试器断点
        }
    }
    
    static removeBreakpoint(id: string): void {
        this.breakpoints.delete(id);
    }
    
    static isBreakpointSet(id: string): boolean {
        return this.breakpoints.has(id);
    }
    
    static listBreakpoints(): string[] {
        return Array.from(this.breakpoints.keys());
    }
}

// 条件调试
class ConditionalDebug {
    static debugIf(condition: boolean, message: string, ...args: any[]): void {
        if (condition) {
            console.log(`🐛 [CONDITIONAL DEBUG] ${message}`, ...args);
            debugger;
        }
    }
    
    static debugWhen<T>(
        value: T,
        predicate: (value: T) => boolean,
        message: string
    ): T {
        if (predicate(value)) {
            console.log(`🐛 [DEBUG WHEN] ${message}`, value);
            debugger;
        }
        return value;
    }
    
    static debugOnce(id: string, message: string, ...args: any[]): void {
        if (!this.debuggedOnce.has(id)) {
            this.debuggedOnce.add(id);
            console.log(`🐛 [DEBUG ONCE] ${message}`, ...args);
            debugger;
        }
    }
    
    private static debuggedOnce = new Set<string>();
}

// 使用示例
class DebuggableService {
    async fetchData(id: string): Promise<any> {
        DebugBreakpoints.setBreakpoint('fetchData:start');
        
        ConditionalDebug.debugIf(
            !id,
            'fetchData called with empty ID'
        );
        
        try {
            const response = await fetch(`/api/data/${id}`);
            
            ConditionalDebug.debugWhen(
                response.status,
                status => status >= 400,
                'HTTP error response received'
            );
            
            const data = await response.json();
            
            ConditionalDebug.debugOnce(
                'first-successful-fetch',
                'First successful data fetch'
            );
            
            return data;
        } catch (error) {
            DebugBreakpoints.setBreakpoint('fetchData:error');
            throw error;
        }
    }
}

7.4 测试中的错误处理

7.4.1 错误测试策略

// 测试工具函数
class TestUtils {
    static async expectError<T extends Error>(
        fn: () => Promise<any> | any,
        errorType?: new (...args: any[]) => T
    ): Promise<T> {
        try {
            const result = await fn();
            throw new Error(`Expected error but got result: ${result}`);
        } catch (error) {
            if (errorType && !(error instanceof errorType)) {
                throw new Error(
                    `Expected error of type ${errorType.name} but got ${error.constructor.name}`
                );
            }
            return error as T;
        }
    }
    
    static async expectNoError(fn: () => Promise<any> | any): Promise<any> {
        try {
            return await fn();
        } catch (error) {
            throw new Error(`Expected no error but got: ${error}`);
        }
    }
    
    static mockError(message: string, type: string = 'Error'): Error {
        const error = new Error(message);
        error.name = type;
        return error;
    }
}

// 错误模拟器
class ErrorSimulator {
    private static errorProbability = 0;
    private static errorTypes: Array<() => Error> = [];
    
    static setErrorProbability(probability: number): void {
        this.errorProbability = Math.max(0, Math.min(1, probability));
    }
    
    static addErrorType(errorFactory: () => Error): void {
        this.errorTypes.push(errorFactory);
    }
    
    static maybeThrow(): void {
        if (Math.random() < this.errorProbability) {
            if (this.errorTypes.length > 0) {
                const randomErrorFactory = this.errorTypes[
                    Math.floor(Math.random() * this.errorTypes.length)
                ];
                throw randomErrorFactory();
            } else {
                throw new Error('Simulated error');
            }
        }
    }
    
    static reset(): void {
        this.errorProbability = 0;
        this.errorTypes = [];
    }
}

// 测试示例
describe('Error Handling Tests', () => {
    beforeEach(() => {
        ErrorSimulator.reset();
    });
    
    describe('UserService', () => {
        it('should handle validation errors correctly', async () => {
            const userService = new UserService();
            
            const error = await TestUtils.expectError(
                () => userService.getUser(''),
                ValidationError
            );
            
            expect(error.field).toBe('id');
            expect(error.code).toBe('VALIDATION_ERROR');
        });
        
        it('should handle network errors correctly', async () => {
            // 模拟网络错误
            ErrorSimulator.setErrorProbability(1);
            ErrorSimulator.addErrorType(() => new NetworkError(
                'Connection timeout',
                '/api/users/123',
                408
            ));
            
            const userService = new UserService();
            
            const error = await TestUtils.expectError(
                () => userService.getUser('123'),
                NetworkError
            );
            
            expect(error.statusCode).toBe(408);
            expect(error.url).toBe('/api/users/123');
        });
        
        it('should succeed when no errors occur', async () => {
            const userService = new UserService();
            
            const result = await TestUtils.expectNoError(
                () => userService.getUser('123')
            );
            
            expect(result.isSuccess).toBe(true);
            if (result.isSuccess) {
                expect(result.value.id).toBe('123');
            }
        });
    });
    
    describe('Result Pattern', () => {
        it('should chain operations correctly with success', async () => {
            const userService = new UserService();
            
            const result = await userService.getUser('123')
                .then(userResult => 
                    userResult.flatMap(user => 
                        userService.updateUser(user.id, { name: 'Updated Name' })
                    )
                );
            
            expect(result.isSuccess).toBe(true);
            if (result.isSuccess) {
                expect(result.value.name).toBe('Updated Name');
            }
        });
        
        it('should handle errors in chain correctly', async () => {
            const userService = new UserService();
            
            const result = await userService.getUser('')
                .then(userResult => 
                    userResult.flatMap(user => 
                        userService.updateUser(user.id, { name: 'Updated Name' })
                    )
                );
            
            expect(result.isFailure).toBe(true);
            if (result.isFailure) {
                expect(result.error).toBeInstanceOf(ValidationError);
            }
        });
    });
});

// 模拟测试框架函数
function describe(name: string, fn: () => void): void {
    console.log(`\n📝 ${name}`);
    fn();
}

function it(name: string, fn: () => Promise<void> | void): void {
    console.log(`  ✓ ${name}`);
    Promise.resolve(fn()).catch(error => {
        console.error(`  ✗ ${name}: ${error.message}`);
    });
}

function beforeEach(fn: () => void): void {
    fn();
}

const expect = {
    toBe: (expected: any) => ({
        toBe: (actual: any) => {
            if (actual !== expected) {
                throw new Error(`Expected ${actual} to be ${expected}`);
            }
        }
    }),
    toBeInstanceOf: (constructor: any) => ({
        toBeInstanceOf: (actual: any) => {
            if (!(actual instanceof constructor)) {
                throw new Error(`Expected ${actual} to be instance of ${constructor.name}`);
            }
        }
    })
};

7.5 生产环境错误监控

7.5.1 错误监控和告警

// 错误监控配置
interface MonitoringConfig {
    apiKey: string;
    environment: string;
    version: string;
    userId?: string;
    sessionId?: string;
    enableConsoleCapture: boolean;
    enableNetworkCapture: boolean;
    enablePerformanceCapture: boolean;
    sampleRate: number;
}

// 错误监控服务
class ErrorMonitoringService {
    private config: MonitoringConfig;
    private errorQueue: any[] = [];
    private isOnline = navigator.onLine;
    
    constructor(config: MonitoringConfig) {
        this.config = config;
        this.setupEventListeners();
        this.startPeriodicFlush();
    }
    
    private setupEventListeners(): void {
        // 网络状态监听
        window.addEventListener('online', () => {
            this.isOnline = true;
            this.flushErrors();
        });
        
        window.addEventListener('offline', () => {
            this.isOnline = false;
        });
        
        // 页面卸载时发送剩余错误
        window.addEventListener('beforeunload', () => {
            this.flushErrors(true);
        });
        
        // 控制台捕获
        if (this.config.enableConsoleCapture) {
            this.captureConsole();
        }
        
        // 网络请求捕获
        if (this.config.enableNetworkCapture) {
            this.captureNetworkRequests();
        }
        
        // 性能监控
        if (this.config.enablePerformanceCapture) {
            this.capturePerformanceMetrics();
        }
    }
    
    captureError(error: Error, context?: any): void {
        // 采样率检查
        if (Math.random() > this.config.sampleRate) {
            return;
        }
        
        const errorData = {
            timestamp: new Date().toISOString(),
            message: error.message,
            stack: error.stack,
            name: error.name,
            context,
            environment: this.config.environment,
            version: this.config.version,
            userId: this.config.userId,
            sessionId: this.config.sessionId,
            url: window.location.href,
            userAgent: navigator.userAgent,
            viewport: {
                width: window.innerWidth,
                height: window.innerHeight
            },
            performance: this.getPerformanceSnapshot()
        };
        
        this.errorQueue.push(errorData);
        
        // 立即发送严重错误
        if (this.isCriticalError(error)) {
            this.flushErrors();
        }
    }
    
    private isCriticalError(error: Error): boolean {
        const criticalPatterns = [
            /chunk.*failed/i,
            /network.*error/i,
            /script.*error/i,
            /out of memory/i
        ];
        
        return criticalPatterns.some(pattern => pattern.test(error.message));
    }
    
    private async flushErrors(useBeacon = false): Promise<void> {
        if (this.errorQueue.length === 0 || !this.isOnline) {
            return;
        }
        
        const errors = [...this.errorQueue];
        this.errorQueue = [];
        
        try {
            if (useBeacon && navigator.sendBeacon) {
                // 使用 sendBeacon 在页面卸载时发送数据
                navigator.sendBeacon(
                    '/api/errors',
                    JSON.stringify({ errors, apiKey: this.config.apiKey })
                );
            } else {
                await fetch('/api/errors', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${this.config.apiKey}`
                    },
                    body: JSON.stringify({ errors })
                });
            }
        } catch (error) {
            // 发送失败,重新加入队列
            this.errorQueue.unshift(...errors);
            console.error('Failed to send error reports:', error);
        }
    }
    
    private startPeriodicFlush(): void {
        setInterval(() => {
            this.flushErrors();
        }, 30000); // 每30秒发送一次
    }
    
    private captureConsole(): void {
        const originalConsoleError = console.error;
        console.error = (...args: any[]) => {
            originalConsoleError.apply(console, args);
            
            const error = new Error(args.join(' '));
            error.name = 'ConsoleError';
            this.captureError(error, { type: 'console', arguments: args });
        };
    }
    
    private captureNetworkRequests(): void {
        const originalFetch = window.fetch;
        window.fetch = async (...args: Parameters<typeof fetch>) => {
            const startTime = performance.now();
            
            try {
                const response = await originalFetch(...args);
                
                if (!response.ok) {
                    const error = new NetworkError(
                        `HTTP ${response.status}: ${response.statusText}`,
                        args[0].toString(),
                        response.status
                    );
                    
                    this.captureError(error, {
                        type: 'network',
                        url: args[0],
                        method: args[1]?.method || 'GET',
                        duration: performance.now() - startTime
                    });
                }
                
                return response;
            } catch (error) {
                const networkError = new NetworkError(
                    error instanceof Error ? error.message : 'Network request failed',
                    args[0].toString()
                );
                
                this.captureError(networkError, {
                    type: 'network',
                    url: args[0],
                    method: args[1]?.method || 'GET',
                    duration: performance.now() - startTime
                });
                
                throw error;
            }
        };
    }
    
    private capturePerformanceMetrics(): void {
        // 监控长任务
        if ('PerformanceObserver' in window) {
            const observer = new PerformanceObserver((list) => {
                for (const entry of list.getEntries()) {
                    if (entry.duration > 50) { // 长任务阈值
                        const error = new Error(`Long task detected: ${entry.duration}ms`);
                        error.name = 'PerformanceWarning';
                        
                        this.captureError(error, {
                            type: 'performance',
                            duration: entry.duration,
                            startTime: entry.startTime,
                            entryType: entry.entryType
                        });
                    }
                }
            });
            
            observer.observe({ entryTypes: ['longtask'] });
        }
    }
    
    private getPerformanceSnapshot(): any {
        if (!('performance' in window)) {
            return null;
        }
        
        const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
        const memory = (performance as any).memory;
        
        return {
            navigation: navigation ? {
                domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
                loadComplete: navigation.loadEventEnd - navigation.loadEventStart,
                firstPaint: this.getFirstPaint(),
                firstContentfulPaint: this.getFirstContentfulPaint()
            } : null,
            memory: memory ? {
                usedJSHeapSize: memory.usedJSHeapSize,
                totalJSHeapSize: memory.totalJSHeapSize,
                jsHeapSizeLimit: memory.jsHeapSizeLimit
            } : null
        };
    }
    
    private getFirstPaint(): number | null {
        const paintEntries = performance.getEntriesByType('paint');
        const firstPaint = paintEntries.find(entry => entry.name === 'first-paint');
        return firstPaint ? firstPaint.startTime : null;
    }
    
    private getFirstContentfulPaint(): number | null {
        const paintEntries = performance.getEntriesByType('paint');
        const firstContentfulPaint = paintEntries.find(entry => entry.name === 'first-contentful-paint');
        return firstContentfulPaint ? firstContentfulPaint.startTime : null;
    }
}

// 使用示例
const monitoring = new ErrorMonitoringService({
    apiKey: 'your-api-key',
    environment: 'production',
    version: '1.0.0',
    userId: 'user-123',
    sessionId: 'session-456',
    enableConsoleCapture: true,
    enableNetworkCapture: true,
    enablePerformanceCapture: true,
    sampleRate: 0.1 // 10% 采样率
});

// 集成到全局错误处理
const globalHandler = GlobalErrorHandler.getInstance();
globalHandler.addErrorListener((error, context) => {
    monitoring.captureError(error, context);
});

7.6 本章练习

练习 1:实现重试机制

// 实现一个通用的重试机制,支持:
// 1. 指数退避
// 2. 最大重试次数
// 3. 条件重试(只对特定错误重试)
// 4. 重试回调

interface RetryOptions {
    maxAttempts: number;
    baseDelay: number;
    maxDelay: number;
    backoffFactor: number;
    shouldRetry?: (error: Error, attempt: number) => boolean;
    onRetry?: (error: Error, attempt: number) => void;
}

class RetryManager {
    // 你的实现
}

// 使用示例
const retryManager = new RetryManager();

const result = await retryManager.execute(
    async () => {
        // 可能失败的操作
        if (Math.random() > 0.7) {
            throw new NetworkError('Connection failed', '/api/data');
        }
        return 'Success!';
    },
    {
        maxAttempts: 5,
        baseDelay: 1000,
        maxDelay: 10000,
        backoffFactor: 2,
        shouldRetry: (error, attempt) => {
            return error instanceof NetworkError && attempt < 3;
        },
        onRetry: (error, attempt) => {
            console.log(`Retry attempt ${attempt}: ${error.message}`);
        }
    }
);

练习 2:实现错误恢复策略

// 实现一个错误恢复系统,支持:
// 1. 多种恢复策略
// 2. 策略链
// 3. 恢复状态跟踪
// 4. 恢复历史记录

enum RecoveryStrategy {
    RETRY = 'retry',
    FALLBACK = 'fallback',
    CIRCUIT_BREAKER = 'circuit_breaker',
    CACHE = 'cache',
    IGNORE = 'ignore'
}

interface RecoveryContext {
    error: Error;
    attempt: number;
    previousResults: any[];
    metadata: Record<string, any>;
}

class ErrorRecoveryManager {
    // 你的实现
}

// 使用示例
const recoveryManager = new ErrorRecoveryManager();

recoveryManager.addStrategy(RecoveryStrategy.RETRY, {
    maxAttempts: 3,
    delay: 1000
});

recoveryManager.addStrategy(RecoveryStrategy.FALLBACK, {
    fallbackValue: 'Default data'
});

const result = await recoveryManager.execute(async () => {
    // 可能失败的操作
    throw new Error('Service unavailable');
});

练习 3:实现错误分析器

// 实现一个错误分析器,支持:
// 1. 错误分类
// 2. 错误趋势分析
// 3. 错误影响评估
// 4. 自动告警

interface ErrorPattern {
    name: string;
    matcher: (error: Error) => boolean;
    severity: 'low' | 'medium' | 'high' | 'critical';
    category: string;
}

interface ErrorAnalysis {
    totalErrors: number;
    errorsByCategory: Record<string, number>;
    errorsBySeverity: Record<string, number>;
    trends: {
        hourly: number[];
        daily: number[];
    };
    topErrors: Array<{
        message: string;
        count: number;
        lastOccurrence: Date;
    }>;
}

class ErrorAnalyzer {
    // 你的实现
}

// 使用示例
const analyzer = new ErrorAnalyzer();

analyzer.addPattern({
    name: 'Network Timeout',
    matcher: (error) => error.message.includes('timeout'),
    severity: 'medium',
    category: 'network'
});

analyzer.addPattern({
    name: 'Memory Leak',
    matcher: (error) => error.message.includes('out of memory'),
    severity: 'critical',
    category: 'performance'
});

// 分析错误
const analysis = analyzer.analyze(errorHistory);
console.log('Error analysis:', analysis);

7.7 本章总结

本章深入探讨了 TypeScript 中的错误处理和调试技巧,包括:

  1. 错误处理基础:了解了 JavaScript 错误类型和自定义错误类
  2. 类型安全的错误处理:学习了 Result 模式和 Option 模式
  3. 调试技巧:掌握了调试工具、装饰器和条件调试
  4. 错误边界和全局错误处理:实现了完整的错误处理系统
  5. 测试中的错误处理:学习了错误测试策略和模拟技术
  6. 生产环境错误监控:构建了错误监控和告警系统

有效的错误处理和调试是构建健壮应用程序的关键。通过类型安全的错误处理模式、完善的调试工具和生产环境监控,我们可以显著提高应用程序的可靠性和可维护性。

下一章我们将学习工程化配置,了解如何在实际项目中配置和优化 TypeScript 开发环境。