Examples
Real-world examples and patterns using go-errors
Examples
This page provides real-world examples of using go-errors in various scenarios. Each example demonstrates best practices and common patterns.
Basic Examples
Simple Error Handling
import { goSync } from 'go-errors';
function divide(a: number, b: number): number {
if (b === 0) throw new Error("Division by zero");
return a / b;
}
// Using go-errors
function safeDivide(a: number, b: number) {
let [result, err] = goSync(() => divide(a, b));
if (err) {
console.log("Division failed:", err.message);
return [null, err] as const;
}
return [result, null] as const;
}
// Usage
let [result1, err] = safeDivide(10, 2);
console.log(result1); // 5
let [result2, err] = safeDivide(10, 0);
console.log(err?.message); // "Division by zero"
API Calls
import { goFetch } from 'go-errors';
interface User {
id: number;
firstName: string;
lastName: string;
fullName: string;
}
async function fetchUser(id: string) {
let [user, err] = await goFetch<User>(`/api/users/${id}`, {
responseTransformer: (data) => ({
...data,
fullName: `${data.firstName} ${data.lastName}`
})
});
if (err) {
return [null, err] as const;
}
return [user, null] as const;
}
// Usage
async function displayUser(id: string) {
let [user, err] = await fetchUser(id);
if (err) {
console.error("Failed to fetch user:", err.message);
return;
}
console.log("User:", user.fullName);
}
Advanced Examples
Custom Error Types
import { goSync } from 'go-errors';
// Define custom error types
class ValidationError extends Error {
constructor(
message: string,
public field: string,
public value: unknown
) {
super(message);
this.name = 'ValidationError';
}
}
class DatabaseError extends Error {
constructor(
message: string,
public details?: unknown
) {
super(message);
this.name = 'DatabaseError';
}
}
// Function that might throw different types of errors
function validateAndSaveUser(user: unknown) {
// Validation
let [validUser, err] = goSync<User, ValidationError>(() => {
if (typeof user !== 'object' || !user) {
throw new ValidationError(
'Invalid user object',
'user',
user
);
}
return user as User;
});
if (err) {
return [null, err] as const;
}
// Database operation
let [savedUser, err] = goSync<User, DatabaseError>(() => {
// Simulate database operation
if (Math.random() < 0.5) {
throw new DatabaseError(
'Database connection failed',
{ timestamp: new Date() }
);
}
return validUser;
});
if (err) {
return [null, err] as const;
}
return [savedUser, null] as const;
}
// Usage with type checking
let [user, err] = validateAndSaveUser({});
if (err) {
if (err instanceof ValidationError) {
console.error(
"Validation failed:",
err.message,
`Field: ${err.field}`,
`Value: ${err.value}`
);
} else if (err instanceof DatabaseError) {
console.error(
"Database error:",
err.message,
err.details
);
}
}
Chaining Operations
import { goFetch } from 'go-errors';
interface User {
id: number;
firstName: string;
lastName: string;
fullName: string;
}
interface Post {
id: number;
userId: number;
title: string;
}
async function fetchUserWithPosts(userId: string) {
// Fetch user
let [user, err] = await goFetch<User>(`/api/users/${userId}`, {
responseTransformer: (data) => ({
...data,
fullName: `${data.firstName} ${data.lastName}`
})
});
if (err) return [null, err] as const;
// Fetch user's posts
let [posts, err] = await goFetch<Post[]>(`/api/users/${userId}/posts`);
if (err) return [null, err] as const;
// Return combined data
return [{
user,
posts,
timestamp: new Date()
}, null] as const;
}
// Usage with destructuring
async function displayUserProfile(userId: string) {
let [data, err] = await fetchUserWithPosts(userId);
if (err) {
console.error("Failed to fetch profile:", err.message);
return;
}
const { user, posts } = data;
console.log(`User: ${user.fullName}`);
console.log(`Posts: ${posts.length}`);
}
File Operations
import { goSync } from 'go-errors';
import { promises as fs } from 'fs';
async function saveConfig(config: object, path: string) {
// Convert to JSON
let [jsonString, err] = goSync(() =>
JSON.stringify(config, null, 2)
);
if (err) {
return [null, err] as const;
}
// Write to file
let [_, err] = await goSync(() =>
fs.writeFile(path, jsonString, 'utf-8')
);
if (err) {
return [null, err] as const;
}
return [true, null] as const;
}
// Usage
async function updateConfig() {
const config = {
api: {
url: 'https://api.example.com',
timeout: 5000
}
};
let [success, err] = await saveConfig(config, './config.json');
if (err) {
console.error("Failed to save config:", err.message);
return;
}
console.log("Config saved successfully");
}
Retry Pattern
import { goFetch } from 'go-errors';
async function withRetry<T, E = Error>(
operation: () => Promise<T>,
maxRetries: number = 3,
delay: number = 1000
): Promise<Result<T, E>> {
let lastError: E | null = null;
for (let i = 0; i < maxRetries; i++) {
let [result, err] = await goFetch<T, E>(operation);
if (!err) {
return [result, null] as const;
}
lastError = err;
if (i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, delay));
}
}
return [null, lastError] as const;
}
// Usage
async function fetchWithRetry(url: string) {
let [data, err] = await withRetry(
() => goFetch(url)
);
if (err) {
console.error("All retries failed:", err.message);
return;
}
console.log("Data fetched successfully:", data);
}
Best Practices Demonstrated
-
Type Safety
- Always use type parameters with
goSync
andgoFetch
- Use custom error types with meaningful context
- Use
as const
assertions for proper type inference
- Always use type parameters with
-
Error Propagation
- Return early when encountering errors
- Preserve error context up the call stack
- Use appropriate error types for different scenarios
-
Async Operations
- Use
goFetch
for HTTP requests - Chain async operations safely
- Implement retry patterns when needed
- Use
-
Code Organization
- Keep error handling separate from business logic
- Use meaningful error types and messages
- Implement reusable error handling patterns
-
Variable Declarations
- Always use
let
for result declarations - Reuse error variable names (typically
err
) - Follow Go-style conventions
- Always use