Error Handling Guide
April 11, 2025 ยท View on GitHub
Result Type
The Result<T, E> type provides type-safe error handling:
class Result<T, E> {
// Create a success result
static Ok<T, E>(value: T): Result<T, E>;
// Create an error result
static Err<T, E>(error: E): Result<T, E>;
// Check if result is success
isOk(): boolean;
// Check if result is error
isErr(): boolean;
// Get value if Ok, throw if Err
unwrap(): T;
// Get error if Err, throw if Ok
unwrapErr(): E;
}
Basic Usage
function divide(a: number, b: number): Result<number, Error> {
if (b === 0) {
return Result.Err(new Error("Division by zero"));
}
return Result.Ok(a / b);
}
// Usage
const result = divide(10, 2);
if (result.isOk()) {
console.log(result.unwrap());
} else {
console.error(result.unwrapErr().message);
}
Pattern Matching
Use pattern matching for elegant error handling:
match result {
Ok(value) => handleSuccess(value),
Err(DatabaseError(e)) => handleDatabaseError(e),
Err(NetworkError(e)) => handleNetworkError(e),
Err(_) => handleUnknownError()
}
Async Error Handling
With Result Type
async function fetchUser(id: string): Promise<Result<User, Error>> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
return Result.Err(new Error(`HTTP ${response.status}`));
}
const user = await response.json();
return Result.Ok(user);
} catch (error) {
return Result.Err(error as Error);
}
}
// Usage
const result = await fetchUser("123");
if (result.isOk()) {
const user = result.unwrap();
processUser(user);
} else {
logError(result.unwrapErr());
}
Error Recovery
async function fetchWithRetry<T>(
fn: () => Promise<T>,
retries: number = 3
): Promise<Result<T, Error>> {
for (let i = 0; i < retries; i++) {
try {
const result = await fn();
return Result.Ok(result);
} catch (error) {
if (i === retries - 1) {
return Result.Err(error as Error);
}
await delay(Math.pow(2, i) * 1000); // Exponential backoff
}
}
return Result.Err(new Error("Max retries exceeded"));
}
Custom Error Types
Define Custom Errors
class DatabaseError extends Error {
constructor(message: string, public code: number) {
super(message);
this.name = "DatabaseError";
}
}
class ValidationError extends Error {
constructor(message: string, public field: string) {
super(message);
this.name = "ValidationError";
}
}
Type-Safe Error Handling
type ApiError = DatabaseError | ValidationError | NetworkError;
function handleApiError(error: ApiError) {
switch (error.constructor) {
case DatabaseError:
handleDatabaseError(error as DatabaseError);
break;
case ValidationError:
handleValidationError(error as ValidationError);
break;
case NetworkError:
handleNetworkError(error as NetworkError);
break;
}
}
Error Boundaries
Component Error Boundaries
class ErrorBoundary {
private errorHandler: (error: Error) => void;
constructor(handler: (error: Error) => void) {
this.errorHandler = handler;
}
wrap<T>(fn: () => T): T {
try {
return fn();
} catch (error) {
this.errorHandler(error as Error);
throw error;
}
}
}
Usage
const boundary = new ErrorBoundary(error => {
console.error("Component error:", error);
showErrorUI(error);
});
boundary.wrap(() => {
// Component code that might throw
render();
});
Logging & Monitoring
Error Logging
class ErrorLogger {
static log(error: Error, context?: any) {
console.error({
name: error.name,
message: error.message,
stack: error.stack,
context,
timestamp: new Date()
});
}
}
Error Monitoring
class ErrorMonitor {
private static errors: Error[] = [];
private static threshold = 10;
static track(error: Error) {
this.errors.push(error);
if (this.errors.length >= this.threshold) {
this.notify();
}
}
private static notify() {
// Send error report to monitoring service
sendErrorReport(this.errors);
this.errors = [];
}
}
Best Practices
- Use
Result<T, E>for expected error cases - Use try/catch for unexpected errors
- Implement proper error recovery strategies
- Create custom error types for different error categories
- Set up error boundaries for component isolation
- Implement comprehensive error logging
- Monitor error patterns in production
Configuration Example
{
"errorHandling": {
"logging": {
"level": "error",
"format": "json",
"destination": "file"
},
"monitoring": {
"enabled": true,
"threshold": 10,
"reportUrl": "/api/errors"
}
}
}