restrict-try-block
Restrict Promise, RxJS, Angular Signal contexts,
Promise.resolve()escape hatches, and physical code lines inside try blocks.
- ⭐️ This rule is included in
plugin:@rdlabo/rules/recommendedpreset.
Restricts asynchronous/reactive processing and physical code lines inside try blocks.
Rule Details
This rule keeps try as a small boundary for synchronous exceptions. By default it reports:
awaitand expressions whose TypeScript type is Promise-likePromise.resolve()calls anywhere, including chains used to convert synchronous exceptions into Promise rejections- expressions whose type or base type is declared by the
rxjspackage, includingObservableandSubjectvariants trystatements inside Angularcomputed()andeffect()callbackstrybodies containing more than three physical code lines
For the try-specific checks, only the try body is inspected. Its catch and finally clauses are not. Nested functions, classes, and nested try statements are separate execution boundaries and are not attributed to the outer try. The Promise.resolve() check applies throughout the file.
Promise rejections should normally be handled by a Promise error boundary such as .catch(). Do not manufacture that boundary with Promise.resolve() to move synchronous failures into the rejection channel:
// incorrect
Promise.resolve()
.then(() => fallibleSynchronousWork())
.catch(handleError);
Keep a synchronous try boundary small and place it in the layer responsible for handling that failure. Return a value or an existing Promise directly instead of normalizing it with Promise.resolve(value).
RxJS errors should be handled through the Observable error channel, such as catchError() or an explicit subscriber error handler.
Promise-like and RxJS type detection uses TypeScript type information when available. Without typed linting, those type-dependent checks are skipped instead of stopping ESLint; syntax-based await, Promise.resolve(), Angular Signal context, and maxLines checks still run. Configure typed linting for full enforcement, for example:
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
},
},
Options
{
allowPromise: false,
allowPromiseResolve: false,
allowRxjs: false,
allowInSignal: false,
maxLines: 3,
}
allowPromise: Allow Promise-like processing andawaitinsidetry.allowPromiseResolve: Disable the dedicated file-widePromise.resolve()check. Inside atrybody,allowPromise: trueis also required because the call is independently Promise-like processing.allowRxjs: Allow values and operations backed by types declared byrxjs. This includesObservable,Subject, and their subclasses.allowInSignal: Allowtryinside inline Angularcomputed()andeffect()callbacks. Aliased and namespace imports from@angular/coreare recognized. Nested function and class bodies are separate execution boundaries.maxLines: Maximum physical code lines in thetrybody, orfalseto disable the size check.
allowPromise: false and allowRxjs: false are fully enforced when typed linting is configured. Without type information, only syntax-based checks such as await remain available for those categories.
The Promise.resolve() check recognizes the unshadowed global Promise and explicit globalThis.Promise, including static bracket notation. It intentionally does not follow aliases. A locally declared or imported value named Promise, or a locally shadowed globalThis, is not treated as the built-in API.
For maxLines, the outer braces, comments, and blank lines are excluded. A unique physical line containing any other token counts once. Internal braces and multiline tokens count, so formatting can affect the result intentionally: the rule keeps the boundary visually small as well as logically narrow.