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