Typed Async Retry Helper

A generic retry helper that preserves the resolved value type, caps attempts, and backs off between failures without losing type information.

TypescriptResilience

Code

snippet
export interface RetryOptions {
  attempts: number;
  delayMs: number;
  isRetryable?: (error: unknown) => boolean;
}

export async function retryAsync<T>(
  task: () => Promise<T>,
  options: RetryOptions,
): Promise<T> {
  const shouldRetry = options.isRetryable ?? (() => true);
  let attempt = 0;
  let lastError: unknown;
  while (attempt < options.attempts) {
    attempt++;
    try {
      return await task();
    } catch (error) {
      lastError = error;
      if (attempt >= options.attempts || !shouldRetry(error)) break;
      await new Promise<void>((resolve) => setTimeout(resolve, options.delayMs * attempt));
    }
  }
  throw lastError;
}