use-unknown-in-catch-callback-variable
Enforce typing arguments in Promise rejection callbacks as
unknown
.
Extending "plugin:@typescript-eslint/strict-type-checked"
in an ESLint configuration enables this rule.
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.
- ❌ Incorrect
- ✅ Correct
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 PlaygroundPromise.reject(new Error('I will reject!')).catch((err: unknown) => {
console.log(err);
});
Open in PlaygroundThe 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'
});
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.
- Flat Config
- Legacy Config
export default tseslint.config({
rules: {
"@typescript-eslint/use-unknown-in-catch-callback-variable": "error"
}
});
module.exports = {
"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.