try-error Documentation

Utilities API

API reference for try-error utility functions and helpers

Type Guards

Type guard functions help TypeScript narrow types and provide runtime type checking for try-error results.

isTryError

Check if a value is a TryError instance with proper type narrowing.

isTryError Type Guardtypescript
1import { isTryError } from 'try-error';
2
3function isTryError<T = any>(value: unknown): value is TryError<T>
4
5// Usage examples
6const result = await tryAsync(() => fetchUser('123'));
7
8if (isTryError(result)) {
9  // TypeScript knows result is TryError
10  console.error('Error:', result.message);
11  console.error('Type:', result.type);
12  console.error('Context:', result.context);
13} else {
14  // TypeScript knows result is User
15  console.log('User:', result.name);
16}
17
18// Generic type checking
19function handleResult<T>(result: TryResult<T, TryError>) {
20  if (isTryError(result)) {
21    return { success: false, error: result };
22  }
23  return { success: true, data: result };
24}

isTrySuccess

Check if a TryResult represents a successful operation.

isTrySuccess Type Guardtypescript
1import { isTrySuccess } from 'try-error';
2
3function isTrySuccess<T, E extends TryError>(
4  result: TryResult<T, E>
5): result is T
6
7// Usage examples
8const results = await Promise.all([
9  tryAsync(() => fetchUser('1')),
10  tryAsync(() => fetchUser('2')),
11  tryAsync(() => fetchUser('3'))
12]);
13
14const successfulResults = results.filter(isTrySuccess);
15// TypeScript knows successfulResults is User[]
16
17const users = results
18  .filter(isTrySuccess)
19  .map(user => user.name); // Type-safe access
20
21// Conditional processing
22function processResults<T>(results: TryResult<T, TryError>[]) {
23  const successful = results.filter(isTrySuccess);
24  const failed = results.filter(isTryError);
25  
26  return {
27    successful,
28    failed,
29    successRate: successful.length / results.length
30  };
31}

hasErrorType

Check if an error has a specific type with type narrowing.

hasErrorType Type Guardtypescript
1import { hasErrorType } from 'try-error';
2
3function hasErrorType<T extends string>(
4  error: TryError,
5  type: T
6): error is TryError & { type: T }
7
8// Usage examples
9const result = await tryAsync(() => validateUser(userData));
10
11if (isTryError(result)) {
12  if (hasErrorType(result, 'ValidationError')) {
13    // Handle validation errors specifically
14    console.log('Validation failed:', result.context.field);
15  } else if (hasErrorType(result, 'NetworkError')) {
16    // Handle network errors
17    console.log('Network issue:', result.context.status);
18  } else {
19    // Handle other errors
20    console.log('Unknown error:', result.type);
21  }
22}
23
24// Multiple type checking
25function isRetryableError(error: TryError): boolean {
26  return hasErrorType(error, 'NetworkError') ||
27         hasErrorType(error, 'TimeoutError') ||
28         hasErrorType(error, 'RateLimitError');
29}

Result Transformers

Transform and manipulate try-error results with functional programming patterns.

mapResult

Transform successful results while preserving errors.

mapResult Transformertypescript
1import { mapResult } from 'try-error';
2
3function mapResult<T, U, E extends TryError>(
4  result: TryResult<T, E>,
5  transform: (value: T) => U
6): TryResult<U, E>
7
8// Usage examples
9const userResult = await tryAsync(() => fetchUser('123'));
10
11// Transform user to display name
12const nameResult = mapResult(userResult, user => user.name);
13
14// Chain transformations
15const upperNameResult = mapResult(nameResult, name => name.toUpperCase());
16
17// Complex transformations
18const userSummaryResult = mapResult(userResult, user => ({
19  id: user.id,
20  displayName: `${user.firstName} ${user.lastName}`,
21  isActive: user.status === 'active',
22  memberSince: new Date(user.createdAt).getFullYear()
23}));
24
25// Async transformations
26async function mapResultAsync<T, U, E extends TryError>(
27  result: TryResult<T, E>,
28  transform: (value: T) => Promise<U>
29): Promise<TryResult<U, E>> {
30  if (isTryError(result)) {
31    return result;
32  }
33  return tryAsync(() => transform(result));
34}

mapError

Transform errors while preserving successful results.

mapError Transformertypescript
1import { mapError } from 'try-error';
2
3function mapError<T, E1 extends TryError, E2 extends TryError>(
4  result: TryResult<T, E1>,
5  transform: (error: E1) => E2
6): TryResult<T, E2>
7
8// Usage examples
9const result = await tryAsync(() => fetchUser('123'));
10
11// Transform network errors to user-friendly messages
12const friendlyResult = mapError(result, error => {
13  if (hasErrorType(error, 'NetworkError')) {
14    return createTryError(
15      'UserFriendlyError',
16      'Unable to load user data. Please try again.',
17      { originalError: error.type }
18    );
19  }
20  return error;
21});
22
23// Add context to errors
24const enrichedResult = mapError(result, error => 
25  enrichError(error, {
26    userId: '123',
27    timestamp: Date.now(),
28    userAgent: navigator.userAgent
29  })
30);
31
32// Convert errors to different types
33const apiResult = mapError(result, error => {
34  const statusCode = getHttpStatusForError(error);
35  return createTryError('ApiError', error.message, {
36    statusCode,
37    originalType: error.type,
38    context: error.context
39  });
40});

flatMapResult

Chain operations that return TryResult, flattening nested results.

flatMapResult Transformertypescript
1import { flatMapResult } from 'try-error';
2
3function flatMapResult<T, U, E extends TryError>(
4  result: TryResult<T, E>,
5  transform: (value: T) => TryResult<U, E>
6): TryResult<U, E>
7
8// Usage examples
9const userResult = await tryAsync(() => fetchUser('123'));
10
11// Chain dependent operations
12const profileResult = flatMapResult(userResult, user =>
13  tryAsync(() => fetchUserProfile(user.id))
14);
15
16// Multiple chained operations
17const fullUserData = await tryAsync(() => fetchUser('123'))
18  .then(result => flatMapResult(result, user =>
19    tryAsync(() => fetchUserProfile(user.id))
20  ))
21  .then(result => flatMapResult(result, profile =>
22    tryAsync(() => fetchUserPreferences(profile.userId))
23  ));
24
25// Conditional chaining
26const conditionalResult = flatMapResult(userResult, user => {
27  if (user.isActive) {
28    return tryAsync(() => fetchActiveUserData(user.id));
29  } else {
30    return tryAsync(() => fetchInactiveUserData(user.id));
31  }
32});
33
34// Error propagation in chains
35async function processUserWorkflow(userId: string) {
36  return tryAsync(() => fetchUser(userId))
37    .then(result => flatMapResult(result, user =>
38      tryAsync(() => validateUser(user))
39    ))
40    .then(result => flatMapResult(result, user =>
41      tryAsync(() => processUser(user))
42    ))
43    .then(result => flatMapResult(result, processed =>
44      tryAsync(() => saveProcessedUser(processed))
45    ));
46}

Result Combinators

Combine multiple try-error results with various strategies.

combineResults

Combine multiple results into a single result containing all successful values.

combineResults Combinatortypescript
1import { combineResults } from 'try-error';
2
3function combineResults<T extends readonly TryResult<any, any>[]>(
4  results: T
5): TryResult<UnwrapResults<T>, TryError>
6
7// Usage examples
8const userResult = await tryAsync(() => fetchUser('123'));
9const profileResult = await tryAsync(() => fetchProfile('123'));
10const prefsResult = await tryAsync(() => fetchPreferences('123'));
11
12// Combine all results
13const combinedResult = combineResults([userResult, profileResult, prefsResult]);
14
15if (isTrySuccess(combinedResult)) {
16  const [user, profile, preferences] = combinedResult;
17  // All operations succeeded
18  console.log('User data loaded:', { user, profile, preferences });
19} else {
20  // At least one operation failed
21  console.error('Failed to load complete user data:', combinedResult.message);
22}
23
24// Named combination
25const namedResult = combineResults({
26  user: userResult,
27  profile: profileResult,
28  preferences: prefsResult
29});
30
31if (isTrySuccess(namedResult)) {
32  const { user, profile, preferences } = namedResult;
33  // Type-safe destructuring
34}
35
36// Partial success handling
37function combineWithPartialSuccess<T extends Record<string, TryResult<any, any>>>(
38  results: T
39): { successful: Partial<UnwrapResults<T>>; failed: TryError[] } {
40  const successful: any = {};
41  const failed: TryError[] = [];
42  
43  for (const [key, result] of Object.entries(results)) {
44    if (isTrySuccess(result)) {
45      successful[key] = result;
46    } else {
47      failed.push(result);
48    }
49  }
50  
51  return { successful, failed };
52}

raceResults

Return the first successful result or all errors if all fail.

raceResults Combinatortypescript
1import { raceResults } from 'try-error';
2
3function raceResults<T>(
4  results: Promise<TryResult<T, TryError>>[]
5): Promise<TryResult<T, TryError[]>>
6
7// Usage examples
8const primaryResult = tryAsync(() => fetchFromPrimaryAPI('123'));
9const fallbackResult = tryAsync(() => fetchFromFallbackAPI('123'));
10const cacheResult = tryAsync(() => fetchFromCache('123'));
11
12// Race for first success
13const fastestResult = await raceResults([
14  primaryResult,
15  fallbackResult,
16  cacheResult
17]);
18
19if (isTrySuccess(fastestResult)) {
20  console.log('Got data from fastest source:', fastestResult);
21} else {
22  console.error('All sources failed:', fastestResult);
23}
24
25// Timeout with fallback
26async function fetchWithTimeout<T>(
27  operation: () => Promise<T>,
28  timeoutMs: number,
29  fallback: () => Promise<T>
30): Promise<TryResult<T, TryError>> {
31  const timeoutPromise = new Promise<TryResult<T, TryError>>(resolve => {
32    setTimeout(() => {
33      resolve(createTryError('TimeoutError', `Operation timed out after ${timeoutMs}ms`));
34    }, timeoutMs);
35  });
36  
37  return raceResults([
38    tryAsync(operation),
39    timeoutPromise,
40    tryAsync(fallback)
41  ]);
42}

sequenceResults

Execute operations in sequence, stopping at the first error.

sequenceResults Combinatortypescript
1import { sequenceResults } from 'try-error';
2
3function sequenceResults<T>(
4  operations: (() => Promise<TryResult<T, TryError>>)[]
5): Promise<TryResult<T[], TryError>>
6
7// Usage examples
8const operations = [
9  () => tryAsync(() => validateInput(data)),
10  () => tryAsync(() => processData(data)),
11  () => tryAsync(() => saveData(data)),
12  () => tryAsync(() => notifySuccess(data))
13];
14
15const sequenceResult = await sequenceResults(operations);
16
17if (isTrySuccess(sequenceResult)) {
18  console.log('All operations completed:', sequenceResult);
19} else {
20  console.error('Sequence failed at step:', sequenceResult);
21}
22
23// Pipeline with transformations
24async function processPipeline<T>(
25  input: T,
26  steps: ((input: any) => Promise<TryResult<any, TryError>>)[]
27): Promise<TryResult<any, TryError>> {
28  let current: TryResult<any, TryError> = input;
29  
30  for (const step of steps) {
31    if (isTryError(current)) {
32      return current;
33    }
34    current = await step(current);
35  }
36  
37  return current;
38}
39
40// Usage
41const pipelineResult = await processPipeline(userData, [
42  data => tryAsync(() => validateUser(data)),
43  data => tryAsync(() => enrichUserData(data)),
44  data => tryAsync(() => saveUser(data)),
45  data => tryAsync(() => sendWelcomeEmail(data))
46]);

Utility Helpers

Additional helper functions for common try-error patterns and operations.

unwrapOr

Extract the value from a result or return a default value.

unwrapOr Helpertypescript
1import { unwrapOr } from 'try-error';
2
3function unwrapOr<T>(result: TryResult<T, TryError>, defaultValue: T): T
4
5// Usage examples
6const userResult = await tryAsync(() => fetchUser('123'));
7
8// Simple default
9const user = unwrapOr(userResult, { id: '123', name: 'Unknown User' });
10
11// Computed default
12const userName = unwrapOr(
13  mapResult(userResult, u => u.name),
14  'Anonymous'
15);
16
17// Function-based default
18function unwrapOrElse<T>(
19  result: TryResult<T, TryError>,
20  getDefault: (error: TryError) => T
21): T {
22  if (isTrySuccess(result)) {
23    return result;
24  }
25  return getDefault(result);
26}
27
28const userWithFallback = unwrapOrElse(userResult, error => {
29  console.warn('Failed to fetch user:', error.message);
30  return createGuestUser();
31});
32
33// Nullable unwrap
34function unwrapOrNull<T>(result: TryResult<T, TryError>): T | null {
35  return isTrySuccess(result) ? result : null;
36}
37
38const maybeUser = unwrapOrNull(userResult);
39if (maybeUser) {
40  console.log('User found:', maybeUser.name);
41}

retry

Retry operations with configurable strategies and backoff.

retry Helpertypescript
1import { retry, RetryOptions } from 'try-error';
2
3interface RetryOptions {
4  maxAttempts: number;
5  delay?: number;
6  backoff?: 'linear' | 'exponential';
7  shouldRetry?: (error: TryError) => boolean;
8}
9
10function retry<T>(
11  operation: () => Promise<T>,
12  options: RetryOptions
13): Promise<TryResult<T, TryError>>
14
15// Usage examples
16const result = await retry(
17  () => fetchUser('123'),
18  {
19    maxAttempts: 3,
20    delay: 1000,
21    backoff: 'exponential'
22  }
23);
24
25// Custom retry logic
26const customRetryResult = await retry(
27  () => processPayment(paymentData),
28  {
29    maxAttempts: 5,
30    delay: 500,
31    shouldRetry: (error) => {
32      // Only retry on network errors or rate limits
33      return hasErrorType(error, 'NetworkError') ||
34             hasErrorType(error, 'RateLimitError');
35    }
36  }
37);
38
39// Retry with jitter
40async function retryWithJitter<T>(
41  operation: () => Promise<T>,
42  options: RetryOptions & { jitter?: boolean }
43): Promise<TryResult<T, TryError>> {
44  let lastError: TryError;
45  
46  for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {
47    const result = await tryAsync(operation);
48    
49    if (isTrySuccess(result)) {
50      return result;
51    }
52    
53    lastError = result;
54    
55    if (attempt < options.maxAttempts && 
56        (!options.shouldRetry || options.shouldRetry(result))) {
57      const delay = calculateDelay(attempt, options);
58      const jitteredDelay = options.jitter ? 
59        delay * (0.5 + Math.random() * 0.5) : delay;
60      await sleep(jitteredDelay);
61    }
62  }
63  
64  return lastError!;
65}

timeout

Add timeout functionality to async operations.

timeout Helpertypescript
1import { timeout } from 'try-error';
2
3function timeout<T>(
4  operation: () => Promise<T>,
5  timeoutMs: number,
6  timeoutMessage?: string
7): Promise<TryResult<T, TryError>>
8
9// Usage examples
10const result = await timeout(
11  () => fetchLargeDataset(),
12  5000, // 5 second timeout
13  'Data fetch timed out'
14);
15
16// Timeout with cleanup
17async function timeoutWithCleanup<T>(
18  operation: (signal: AbortSignal) => Promise<T>,
19  timeoutMs: number
20): Promise<TryResult<T, TryError>> {
21  const controller = new AbortController();
22  
23  const timeoutId = setTimeout(() => {
24    controller.abort();
25  }, timeoutMs);
26  
27  try {
28    const result = await tryAsync(() => operation(controller.signal));
29    clearTimeout(timeoutId);
30    return result;
31  } catch (error) {
32    clearTimeout(timeoutId);
33    if (controller.signal.aborted) {
34      return createTryError('TimeoutError', `Operation timed out after ${timeoutMs}ms`);
35    }
36    throw error;
37  }
38}
39
40// Progressive timeout
41async function progressiveTimeout<T>(
42  operation: () => Promise<T>,
43  timeouts: number[]
44): Promise<TryResult<T, TryError>> {
45  for (const timeoutMs of timeouts) {
46    const result = await timeout(operation, timeoutMs);
47    if (isTrySuccess(result)) {
48      return result;
49    }
50    
51    // If it's not a timeout error, don't retry
52    if (!hasErrorType(result, 'TimeoutError')) {
53      return result;
54    }
55  }
56  
57  return createTryError(
58    'TimeoutError',
59    `Operation failed after all timeout attempts: ${timeouts.join(', ')}ms`
60  );
61}

Best Practices

✅ Do

  • • Use type guards for proper type narrowing
  • • Combine results when you need all operations to succeed
  • • Use mapResult for transforming successful values
  • • Use flatMapResult for chaining dependent operations
  • • Implement retry logic for transient failures
  • • Add timeouts to prevent hanging operations

❌ Don't

  • • Ignore type guards and manually check error properties
  • • Use unwrapOr with expensive default value computations
  • • Retry operations that will never succeed
  • • Set overly aggressive timeouts for normal operations
  • • Chain too many operations without error handling
  • • Use combinators when simple sequential logic is clearer

Related Pages

Error Creation API

Learn about creating and working with TryError objects

View Error API →

TypeScript Types

Complete reference for all TypeScript types and interfaces

View Types Reference →