@typescript-eslint/prefer-promise-reject-errors
Require an Error as the reason when a promise is rejected
Also called typescript-eslint/prefer-promise-reject-errors, typescript/prefer-promise-reject-errors
A rejected promise turns into a throw at the await. If the reason is a string, the catch block gets a value with no stack trace and no message, and error instanceof Error is false.
The rule checks Promise.reject(...) and calls to reject inside new Promise((resolve, reject) => ...). Rejecting with nothing is reported too.
This is prefer-promise-reject-errors with types. It looks at the reason's type, so a variable that holds a string is reported and a class that extends Error isn't.
With bunfig.toml, turning this rule on runs it in TypeScript files and prefer-promise-reject-errors in JavaScript files, so nothing is reported twice. With an ESLint config, turn the other rule off when you use this one.
bun lint --type-aware turns this rule on in TypeScript files.
Configure#
Off by default. This rule needs types, so turning it on makes bun lint type check your code first.
[lint.rules]
"@typescript-eslint/prefer-promise-reject-errors" = "error" # or "warn"Every option, set to its default:
[lint.rules]
"@typescript-eslint/prefer-promise-reject-errors" = ["error", {
allowEmptyReject = false,
allowThrowingAny = false,
allowThrowingUnknown = false,
allow = [], # list of strings or objects
}]Examples#
function load(url: string, reason: string) {
if (!url) return Promise.reject("missing url")Expected the Promise rejection reason to be an Error.;
if (url === "/") return Promise.reject()Expected the Promise rejection reason to be an Error.;
return new Promise((resolve, reject) => {
reject(reason)Expected the Promise rejection reason to be an Error.;
});
}class HttpError extends Error {}
function load(url: string) {
if (!url) return Promise.reject(new Error("missing url"));
return new Promise((resolve, reject) => {
reject(new HttpError("not found"));
});
}Options#
| Option | Default | What it does |
|---|---|---|
allowEmptyReject | false | Allow Promise.reject() and reject() without a reason. |
allowThrowingAny | false | Allow a reason of type any. |
allowThrowingUnknown | false | Allow a reason of type unknown. |
allow | [] | Other types that are allowed as a reason. |
With strict, the value in a catch block is unknown, so passing it on is reported:
async function retry(task: () => Promise<void>) {
try {
await task();
} catch (error) {
return Promise.reject(error)Expected the Promise rejection reason to be an Error.;
}
}With allowThrowingUnknown: true it's allowed:
{ "allowThrowingUnknown": true }No problemsasync function retry(task: () => Promise<void>) {
try {
await task();
} catch (error) {
return Promise.reject(error);
}
}Each allow entry is a type name, or an object that also says where the type comes from: { "from": "file", "name": "Failure" }, { "from": "lib", "name": "Date" }, or { "from": "package", "name": "Failure", "package": "some-package" }. With the first of these, this is allowed:
{ "allow": [{ "from": "file", "name": "Failure" }] }No problemsinterface Failure {
code: number;
}
function fail(failure: Failure) {
return Promise.reject(failure);
}