Skip to main content

use-unknown-in-catch-callback-variable

Enforce typing arguments in Promise rejection callbacks as unknown.

🔧

Some problems reported by this rule are automatically fixable by the --fix ESLint command line option.

💡

Some problems reported by this rule are manually fixable by editor suggestions.

💭

This rule requires type information to run.

This rule enforces that you always use the unknown type for the parameter of a Promise rejection callback.

Promise.reject(new Error('I will reject!')).catch(err => {
console.log(err);
});

Promise.reject(new Error('I will reject!')).catch((err: any) => {
console.log(err);
});

Promise.reject(new Error('I will reject!')).catch((err: Error) => {
console.log(err);
});

Promise.reject(new Error('I will reject!')).then(
result => {
console.log(result);
},
err => {
console.log(err);
},
);
Open in Playground

The reason for this rule is to enable programmers to impose constraints on Promise error handling analogously to what TypeScript provides for ordinary exception handling.

For ordinary exceptions, TypeScript treats the catch variable as any by default. However, unknown would be a more accurate type, so TypeScript introduced the useUnknownInCatchVariables compiler option to treat the catch variable as unknown instead.

try {
throw x;
} catch (err) {
// err has type 'any' with useUnknownInCatchVariables: false
// err has type 'unknown' with useUnknownInCatchVariables: true
}

The Promise analog of the try-catch block, Promise.prototype.catch(), is not affected by the useUnknownInCatchVariables compiler option, and its "catch variable" will always have the type any.

Promise.reject(x).catch(err => {
// err has type 'any' regardless of `useUnknownInCatchVariables`
});

However, you can still provide an explicit type annotation, which lets you achieve the same effect as the useUnknownInCatchVariables option does for synchronous catch variables.

Promise.reject(x).catch((err: unknown) => {
// err has type 'unknown'
});
info

There is actually a way to have the catch() and then() callback variables use the unknown type without an explicit type annotation at the call sites, but it has the drawback that it involves overriding global type declarations. For example, the library better-TypeScript-lib sets this up globally for your project (see the relevant lines in the better-TypeScript-lib source code for details on how).

For further reading on this, you may also want to look into the discussion in the proposal for this rule and this TypeScript issue on typing catch callback variables as unknown.

eslint.config.mjs
export default tseslint.config({
rules: {
"@typescript-eslint/use-unknown-in-catch-callback-variable": "error"
}
});

Try this rule in the playground ↗

Options

This rule is not configurable.

When Not To Use It

If your codebase is not yet able to enable useUnknownInCatchVariables, it likely would be similarly difficult to enable this rule.

If you have modified the global type declarations in order to make then() and catch() callbacks use the unknown type without an explicit type annotation, you do not need this rule.


Type checked lint rules are more powerful than traditional lint rules, but also require configuring type checked linting.

See Troubleshooting > Linting with Type Information > Performance if you experience performance degradations after enabling type checked rules.

Resources