try-error Documentation

Asynchronous Operations

API reference for handling asynchronous operations with try-error

tryAsync

Function Signaturetypescript
function tryAsync<T>(fn: () => Promise<T>): Promise<TryResult<T, TryError>>

Executes an asynchronous function and returns a Promise that resolves to either the result or a TryError if the promise rejects.

Parameters

  • fn: () => Promise<T> - The async function to execute

Returns

Promise<TryResult<T, TryError>> - Promise resolving to either the result or a TryError

Examples

tryAsync Examplestypescript
1import { tryAsync, isTryError } from 'try-error';
2
3// API calls
4const fetchUser = async (id: string) => {
5  const result = await tryAsync(() => fetch(`/api/users/${id}`));
6  if (isTryError(result)) {
7    console.error('Fetch failed:', result.message);
8    return null;
9  }
10  
11  const jsonResult = await tryAsync(() => result.json());
12  if (isTryError(jsonResult)) {
13    console.error('JSON parse failed:', jsonResult.message);
14    return null;
15  }
16  
17  return jsonResult;
18};
19
20// File operations (Node.js)
21const readFileAsync = async (path: string) => {
22  const fs = require('fs').promises;
23  const result = await tryAsync(() => fs.readFile(path, 'utf8'));
24  return result;
25};
26
27// Database operations
28const saveUser = async (user: User) => {
29  const result = await tryAsync(() => db.users.create(user));
30  if (isTryError(result)) {
31    console.error('Database error:', result.message);
32    throw new Error('Failed to save user');
33  }
34  return result;
35};

Common Async Patterns

Sequential Operations

Sequential Operationstypescript
async function processUserData(userId: string) {
  // Step 1: Fetch user
  const userResult = await tryAsync(() => fetchUser(userId));
  if (isTryError(userResult)) return userResult;
  
  // Step 2: Fetch user preferences
  const prefsResult = await tryAsync(() => fetchPreferences(userResult.id));
  if (isTryError(prefsResult)) return prefsResult;
  
  // Step 3: Combine data
  const combinedResult = trySync(() => combineUserData(userResult, prefsResult));
  return combinedResult;
}

Parallel Operations

Parallel Operationstypescript
1async function fetchUserProfile(userId: string) {
2  // Start all operations in parallel
3  const [userResult, prefsResult, postsResult] = await Promise.all([
4    tryAsync(() => fetchUser(userId)),
5    tryAsync(() => fetchPreferences(userId)),
6    tryAsync(() => fetchUserPosts(userId))
7  ]);
8  
9  // Check each result
10  if (isTryError(userResult)) {
11    console.error('User fetch failed:', userResult.message);
12    return userResult;
13  }
14  
15  if (isTryError(prefsResult)) {
16    console.error('Preferences fetch failed:', prefsResult.message);
17    // Continue with default preferences
18  }
19  
20  if (isTryError(postsResult)) {
21    console.error('Posts fetch failed:', postsResult.message);
22    // Continue with empty posts
23  }
24  
25  return {
26    user: userResult,
27    preferences: isTryError(prefsResult) ? defaultPrefs : prefsResult,
28    posts: isTryError(postsResult) ? [] : postsResult
29  };
30}

Retry Logic

Retry Logic Implementationtypescript
1async function fetchWithRetry<T>(
2  operation: () => Promise<T>,
3  maxRetries: number = 3
4): Promise<TryResult<T, TryError>> {
5  for (let attempt = 1; attempt <= maxRetries; attempt++) {
6    const result = await tryAsync(operation);
7    
8    if (!isTryError(result)) {
9      return result; // Success
10    }
11    
12    if (attempt === maxRetries) {
13      return result; // Final attempt failed
14    }
15    
16    // Wait before retry
17    await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
18  }
19  
20  // This should never be reached, but TypeScript requires it
21  return createTryError('RETRY_EXHAUSTED', 'All retry attempts failed');
22}

Timeout Handling

Timeout Handlingtypescript
async function fetchWithTimeout<T>(
  operation: () => Promise<T>,
  timeoutMs: number = 5000
): Promise<TryResult<T, TryError>> {
  const timeoutPromise = new Promise<never>((_, reject) => {
    setTimeout(() => reject(new Error(`Operation timed out after ${timeoutMs}ms`)), timeoutMs);
  });
  
  const result = await tryAsync(() => 
    Promise.race([operation(), timeoutPromise])
  );
  
  return result;
}

Error Handling Strategies

Graceful Degradation

Graceful Degradation Patterntypescript
1async function loadDashboard(userId: string) {
2  // Critical data - must succeed
3  const userResult = await tryAsync(() => fetchUser(userId));
4  if (isTryError(userResult)) {
5    return { error: 'Failed to load user data', user: null };
6  }
7  
8  // Optional data - can fail gracefully
9  const [notificationsResult, analyticsResult] = await Promise.all([
10    tryAsync(() => fetchNotifications(userId)),
11    tryAsync(() => fetchAnalytics(userId))
12  ]);
13  
14  return {
15    user: userResult,
16    notifications: isTryError(notificationsResult) ? [] : notificationsResult,
17    analytics: isTryError(analyticsResult) ? null : analyticsResult,
18    warnings: [
19      ...(isTryError(notificationsResult) ? ['Failed to load notifications'] : []),
20      ...(isTryError(analyticsResult) ? ['Failed to load analytics'] : [])
21    ]
22  };
23}

Circuit Breaker Pattern

Circuit Breaker Implementationtypescript
1class CircuitBreaker {
2  private failures = 0;
3  private lastFailureTime = 0;
4  private readonly threshold = 5;
5  private readonly timeout = 60000; // 1 minute
6  
7  async execute<T>(operation: () => Promise<T>): Promise<TryResult<T, TryError>> {
8    if (this.isOpen()) {
9      return createTryError('CIRCUIT_OPEN', 'Circuit breaker is open');
10    }
11    
12    const result = await tryAsync(operation);
13    
14    if (isTryError(result)) {
15      this.recordFailure();
16    } else {
17      this.reset();
18    }
19    
20    return result;
21  }
22  
23  private isOpen(): boolean {
24    return this.failures >= this.threshold && 
25           Date.now() - this.lastFailureTime < this.timeout;
26  }
27  
28  private recordFailure(): void {
29    this.failures++;
30    this.lastFailureTime = Date.now();
31  }
32  
33  private reset(): void {
34    this.failures = 0;
35    this.lastFailureTime = 0;
36  }
37}

Best Practices

✅ Do

  • • Always await tryAsync calls
  • • Check for errors before using async results
  • • Use Promise.all for parallel operations
  • • Implement proper timeout handling
  • • Consider retry logic for transient failures
  • • Use graceful degradation for non-critical operations

❌ Don't

  • • Forget to await tryAsync calls
  • • Use tryAsync for synchronous operations
  • • Ignore error cases in async flows
  • • Chain too many sequential operations without error handling
  • • Mix tryAsync with traditional try/catch unnecessarily

Related APIs

trySync

For synchronous operations that might throw

View trySync →

Error Creation

Creating custom errors and error factories

View Error API →