{"id":15251,"library":"typescript-retry-decorator","title":"TypeScript Retry Decorator","description":"The `typescript-retry-decorator` library provides a simple, zero-dependency decorator for adding retry logic to TypeScript functions, inspired by Spring-Retry. It supports both synchronous and asynchronous (Promise-returning) functions, making it suitable for Node.js and modern browser environments. The current stable version is 2.5.4, with releases occurring periodically, often addressing compatibility with newer TypeScript features or Node.js module systems, as seen in recent 2.5.x patches. Its key differentiators include its lightweight nature (no external dependencies), comprehensive test coverage, and support for both legacy and TypeScript 5+ standard decorators, offering various backoff policies (fixed, exponential with jitter) and custom error handling for retry conditions.","status":"active","version":"2.5.4","language":"javascript","source_language":"en","source_url":"https://github.com/vcfvct/typescript-retry-decorator","tags":["javascript","typescirpt","decorator","retry","typescript"],"install":[{"cmd":"npm install typescript-retry-decorator","lang":"bash","label":"npm"},{"cmd":"yarn add typescript-retry-decorator","lang":"bash","label":"yarn"},{"cmd":"pnpm add typescript-retry-decorator","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"From v2.5.4, proper ESM module detection is ensured with `type: module` in `dist/esm/package.json`. Earlier CJS `require` might fail in some ESM-enabled environments or require specific bundler configurations for dual package support.","wrong":"const { Retry } = require('typescript-retry-decorator');","symbol":"Retry","correct":"import { Retry } from 'typescript-retry-decorator';"},{"note":"These are enum values or type definitions. Direct imports from sub-paths are generally not recommended as the package uses `exports` for controlled access to its dual CJS/ESM builds.","wrong":"import { FixedBackOffPolicy } from 'typescript-retry-decorator/dist/cjs';","symbol":"FixedBackOffPolicy, ExponentialBackOffPolicy","correct":"import { FixedBackOffPolicy, ExponentialBackOffPolicy } from 'typescript-retry-decorator';"},{"note":"Importing types explicitly using `import type` is recommended for better tree-shaking and clarity in TypeScript projects.","symbol":"RetryOptions","correct":"import type { RetryOptions } from 'typescript-retry-decorator';"}],"quickstart":{"code":"import { Retry, ExponentialBackOffPolicy } from 'typescript-retry-decorator';\n\n// Simulate an external service call that fails a few times\nlet callCount = 0;\nasync function unreliableServiceCall(data: string): Promise<string> {\n  callCount++;\n  if (callCount < 3) { // Fail for the first 2 calls\n    console.log(`Attempt ${callCount}: Service call failed for data: ${data}`);\n    throw new Error('Service temporarily unavailable');\n  }\n  console.log(`Attempt ${callCount}: Service call succeeded for data: ${data}`);\n  return `Processed: ${data}`;\n}\n\nclass MyService {\n  @Retry({\n    maxAttempts: 5,\n    backOff: 100, // initial backoff 100ms\n    backOffPolicy: ExponentialBackOffPolicy,\n    exponentialOption: { multiplier: 2, maxInterval: 1000 }, // Intervals: 100, 200, 400, 800, 1000, 1000...\n    doRetry: (e: any) => {\n      console.log(`Checking error for retry: ${e.message}`);\n      return e.message === 'Service temporarily unavailable';\n    },\n    value: [Error], // Retry on any Error class\n    useOriginalError: true, // Throw original error if max attempts reached\n    useConsoleLogger: true\n  })\n  async processData(input: string): Promise<string> {\n    console.log(`Executing processData for input: ${input}`);\n    return unreliableServiceCall(input);\n  }\n}\n\nasync function runExample() {\n  const service = new MyService();\n  try {\n    const result = await service.processData('example-data');\n    console.log(`Final Result: ${result}`);\n  } catch (error: any) {\n    console.error(`Operation failed after retries: ${error.message}`);\n  } finally {\n    callCount = 0; // Reset for potential re-runs\n  }\n}\n\nrunExample();","lang":"typescript","description":"Demonstrates applying the `@Retry` decorator to an asynchronous method, configured with exponential backoff and custom retry conditions for transient errors."},"warnings":[{"fix":"Ensure your project is configured for proper ESM consumption (e.g., `\"type\": \"module\"` in `package.json`, using explicit `.js` extensions where needed for Node.js ESM) or explicitly target the CJS build if your tooling requires it (though direct subpath imports are not officially supported). Update to the latest patch version (>=2.5.4) for best compatibility.","message":"Post v2.5.2, significant changes were made to how the package handles CommonJS (CJS) and ES Modules (ESM) builds. Versions 2.5.3 and 2.5.4 specifically addressed issues with `.js` extensions in imports and the `type: module` declaration, which might break existing CJS `require()` usage or older ESM bundler setups.","severity":"breaking","affected_versions":">=2.5.2"},{"fix":"For legacy decorators, ensure `\"experimentalDecorators\": true` and `\"emitDecoratorMetadata\": true` are set in `tsconfig.json`. For TS5+ standard decorators, no special `tsconfig.json` flags are needed, but ensure your TypeScript version is 5.0 or higher.","message":"The library supports both TypeScript's legacy experimental decorators (`experimentalDecorators` compiler option) and the new TypeScript 5+ standard decorators. Incorrect `tsconfig.json` setup can lead to decorator compilation failures or runtime issues.","severity":"gotcha","affected_versions":"*"},{"fix":"Set `useOriginalError: true` in the `@Retry` decorator options if you need the original error to propagate on final failure instead of `MaxAttemptsError`.","message":"By default, when `maxAttempts` are exhausted, the decorator throws a `MaxAttemptsError`. To rethrow the original exception that caused the last failure, the `useOriginalError` option must be set to `true`.","severity":"gotcha","affected_versions":"*"},{"fix":"Review code interacting with the retry decorator, especially error handlers and decorator options, to ensure null and undefined values are handled explicitly, adhering to stricter TypeScript rules.","message":"Version 2.4.2 enabled `strictNullChecks` for the package itself, potentially exposing previously overlooked null/undefined handling issues in consuming applications that relied on more lenient type checking.","severity":"gotcha","affected_versions":">=2.4.2"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"If using Node.js and an specific CommonJS setup, try updating Node.js, your bundler, or TypeScript configuration. For most modern setups, switch to `import { Retry } from 'typescript-retry-decorator';`. Ensure `package.json` for your project either has `\"type\": \"module\"` (for ESM) or correctly handles CJS interop if `\"type\": \"commonjs\"`.","cause":"Attempting to import and use the library in a CommonJS environment that doesn't correctly resolve the dual CJS/ESM package exports, especially after recent ESM compatibility fixes (v2.5.x). This often happens when `require()` is used on a package primarily structured for ESM.","error":"TypeError: (0 , _typescriptRetryDecorator.Retry) is not a function"},{"fix":"Ensure `\"experimentalDecorators\": true` and `\"emitDecoratorMetadata\": true` are present in your `tsconfig.json` if using TypeScript versions prior to 5.0 or opting into legacy decorators. If using TS 5.0+, ensure no conflicting experimental decorator flags are set and your TypeScript version is correctly configured.","cause":"Incorrect `tsconfig.json` configuration for decorators, particularly missing `\"experimentalDecorators\": true` or `\"emitDecoratorMetadata\": true` when using legacy decorators, or issues with TS5+ standard decorator setup.","error":"Decorator 'Retry' is not a valid decorator factory."},{"fix":"Ensure the `value` option is an array containing constructor functions of `Error` types, like `value: [Error, CustomTransientError]`.","cause":"Passing a string or simple object to the `value` option instead of an array of actual `Error` constructor functions (e.g., `Error`, `MyCustomError`). The `value` option expects an array of error *classes* to retry on.","error":"TS2345: Argument of type 'string' is not assignable to parameter of type 'ErrorConstructor | undefined'."}],"ecosystem":"npm"}