return-await
Enforce consistent awaiting of returned promises.
在 ESLint 配置 中扩展"plugin:@typescript-eslint/strict-type-checked"
可启用此规则。
此规则报告的一些问题可通过 --fix
ESLint 命令行选项自动修复。
此规则报告的一些问题可以通过编辑器 建议 手动修复。
该规则需要 类型信息 才能运行,但这会带来性能方面的权衡。
在 async
函数中,返回承诺封装的值或直接返回值都是有效的,这两者最终都会产生具有相同履行值的承诺。返回值而不是承诺封装的值可以有几个微妙的好处:
¥In async
functions, it is valid to return a promise-wrapped value or a value directly, both of which ultimately produce a promise with the same fulfillment value. Returning a value rather than a promise-wrapped value can have several subtle benefits:
-
返回等待的承诺 改进堆栈跟踪信息。
¥Returning an awaited promise improves stack trace information.
-
当
return
语句在try...catch
中时,等待承诺可以捕获承诺的拒绝,而不是将错误留给调用者。¥When the
return
statement is intry...catch
, awaiting the promise allows the promise's rejection to be caught instead of leaving the error to the caller. -
与普遍看法相反,
return await promise;
就是 至少与直接返回承诺一样快。¥Contrary to popular belief,
return await promise;
is at least as fast as directly returning the promise.
此规则强 制一致处理是否在返回承诺之前等待承诺。
¥This rule enforces consistent handling of whether to await promises before returning them.
此规则曾被视为(现已弃用的)ESLint 核心规则 no-return-await
的扩展。如果没有类型信息,no-return-await
唯一可以标记的情况是中性到负值,这最终导致其弃用。相比之下,通过访问类型信息,@typescript-eslint/return-await
提供了足够的正值,使其在我们的严格预设中占有一席之地。
¥This rule used to be considered an extension of the (now-deprecated) ESLint core rule no-return-await
.
Without type information, the only situations that could be flagged by no-return-await
were of neutral-to-negative value, which eventually led to its deprecation.
In contrast, with access to type information, @typescript-eslint/return-await
delivers enough positive value to earn it a spot in our strict preset.
如果你以前使用过 no-return-await
,则此规则的 in-try-catch
选项的行为与 no-return-await
规则最接近。
¥If you previously used no-return-await
, this rule's in-try-catch
option has the closest behavior to the no-return-await
rule.
- Flat Config
- Legacy Config
export default tseslint.config({
rules: {
"@typescript-eslint/return-await": "error"
}
});
module.exports = {
"rules": {
"@typescript-eslint/return-await": "error"
}
};
在线运行试试这个规则 ↗
选项
This rule accepts the following options, and has more strict settings in the strict and strict-type-checked configs.
type Options = [
/** Disallows awaiting any returned promises. */
| 'never'
/** In error-handling contexts, the rule enforces that returned promises must be awaited. In ordinary contexts, the rule does not enforce any particular behavior around whether returned promises are awaited. */
| 'error-handling-correctness-only'
/** In error-handling contexts, the rule enforces that returned promises must be awaited. In ordinary contexts, the rule enforces that returned promises _must not_ be awaited. */
| 'in-try-catch'
/** Requires that all returned promises be awaited. */
| 'always',
];
const defaultOptionsRecommended: Options = ['in-try-catch'];
// These options are merged on top of the recommended defaults
const defaultOptionsStrict: Options = ['error-handling-correctness-only'];
¥Options
type Options =
| 'in-try-catch'
| 'always'
| 'error-handling-correctness-only'
| 'never';
const defaultOptions: Options = 'in-try-catch';
此规则中的选项区分 "普通上下文" 和 "错误处理上下文"。错误处理上下文是返回未等待的承诺会导致与异常/拒绝有关的意外控制流的任何地方。有关每个选项的部分,请参阅详细示例。
¥The options in this rule distinguish between "ordinary contexts" and "error-handling contexts". An error-handling context is anywhere where returning an unawaited promise would cause unexpected control flow regarding exceptions/rejections. See detailed examples in the sections for each option.
-
如果你在
try
块内返回一个承诺,则应该等待它以按预期触发后续的catch
或finally
块。¥If you return a promise within a
try
block, it should be awaited in order to trigger subsequentcatch
orfinally
blocks as expected. -
如果你在
catch
块内返回一个承诺,并且有一个finally
块,则应该等待它以按预期触发finally
块。¥If you return a promise within a
catch
block, and there is afinally
block, it should be awaited in order to trigger thefinally
block as expected. -
如果你在
using
或await using
声明与其 范围结束之间返回一个承诺,则应该等待它,因为它的行为相当于封装在try
块中后跟finally
的代码。¥If you return a promise between a
using
orawait using
declaration and the end of its scope, it should be awaited, since it behaves equivalently to code wrapped in atry
block followed by afinally
.
普通上下文是可能返回承诺的任何其他位置。在普通上下文中是否等待返回的承诺的选择主要是风格上的。
¥Ordinary contexts are anywhere else a promise may be returned. The choice of whether to await a returned promise in an ordinary context is mostly stylistic.
在定义这些术语后,选项可以总结如下:
¥With these terms defined, the options may be summarized as follows:
选项 | 普通上下文 (风格偏好🎨) | 错误处理上下文 (捕获错误🐛) | 我应该使用此选项吗? |
---|---|---|---|
always | return await promise; | return await promise; | ✅ 是的! |
in-try-catch | return promise; | return await promise; | ✅ 是的! |
error-handling-correctness-only | 不关心 🤷 | return await promise; | 🟡 可以使用,但上述选项会更好。 |
never | return promise; | return promise; (⚠️ 这种行为可能有害⚠️) | ❌ 不。此选项已弃用。 |
in-try-catch
在错误处理上下文中,规则强制要求必须等待返回的承诺。在普通情况下,规则强制要求不能等待返回的承诺。
¥In error-handling contexts, the rule enforces that returned promises must be awaited. In ordinary contexts, the rule enforces that returned promises must not be awaited.
如果你出于风格原因更喜欢较短的 return promise
形式,那么这是一个不错的选择,无论在哪里使用都是安全的。
¥This is a good option if you prefer the shorter return promise
form for stylistic reasons, wherever it's safe to use.
带有 in-try-catch
的代码示例:
¥Examples of code with in-try-catch
:
- ❌ Incorrect
- ✅ Correct
async function invalidInTryCatch1() {
try {
return Promise.reject('try');
} catch (e) {
// Doesn't execute due to missing await.
}
}
async function invalidInTryCatch2() {
try {
throw new Error('error');
} catch (e) {
// Unnecessary await; rejections here don't impact control flow.
return await Promise.reject('catch');
}
}
// Prints 'starting async work', 'cleanup', 'async work done'.
async function invalidInTryCatch3() {
async function doAsyncWork(): Promise<void> {
console.log('starting async work');
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('async work done');
}
try {
throw new Error('error');
} catch (e) {
// Missing await.
return doAsyncWork();
} finally {
console.log('cleanup');
}
}
async function invalidInTryCatch4() {
try {
throw new Error('error');
} catch (e) {
throw new Error('error2');
} finally {
// Unnecessary await; rejections here don't impact control flow.
return await Promise.reject('finally');
}
}
async function invalidInTryCatch5() {
return await Promise.resolve('try');
}
async function invalidInTryCatch6() {
return await 'value';
}
async function invalidInTryCatch7() {
using x = createDisposable();
return Promise.reject('using in scope');
}
Open in Playgroundasync function validInTryCatch1() {
try {
return await Promise.reject('try');
} catch (e) {
// Executes as expected.
}
}
async function validInTryCatch2() {
try {
throw new Error('error');
} catch (e) {
return Promise.reject('catch');
}
}
// Prints 'starting async work', 'async work done', 'cleanup'.
async function validInTryCatch3() {
async function doAsyncWork(): Promise<void> {
console.log('starting async work');
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('async work done');
}
try {
throw new Error('error');
} catch (e) {
return await doAsyncWork();
} finally {
console.log('cleanup');
}
}
async function validInTryCatch4() {
try {
throw new Error('error');
} catch (e) {
throw new Error('error2');
} finally {
return Promise.reject('finally');
}
}
async function validInTryCatch5() {
return Promise.resolve('try');
}
async function validInTryCatch6() {
return 'value';
}
async function validInTryCatch7() {
using x = createDisposable();
return await Promise.reject('using in scope');
}
Open in Playgroundalways
要求等待所有返回的承诺。
¥Requires that all returned promises be awaited.
如果你喜欢始终等待承诺的一致性,或者不想考虑错误处理上下文和普通上下文之间的区别,那么这是一个不错的选择。
¥This is a good option if you like the consistency of simply always awaiting promises, or prefer not having to consider the distinction between error-handling contexts and ordinary contexts.
带有 always
的代码示例:
¥Examples of code with always
:
- ❌ Incorrect
- ✅ Correct
async function invalidAlways1() {
try {
return Promise.resolve('try');
} catch (e) {}
}
async function invalidAlways2() {
return Promise.resolve('try');
}
async function invalidAlways3() {
return await 'value';
}
Open in Playgroundasync function validAlways1() {
try {
return await Promise.resolve('try');
} catch (e) {}
}
async function validAlways2() {
return await Promise.resolve('try');
}
async function validAlways3() {
return 'value';
}
Open in Playgrounderror-handling-correctness-only
在错误处理上下文中,规则强制要求必须等待返回的承诺。在普通情况下,规则不会强制任何特定的行为,即是否等待返回的承诺。
¥In error-handling contexts, the rule enforces that returned promises must be awaited. In ordinary contexts, the rule does not enforce any particular behavior around whether returned promises are awaited.
如果你只想从规则在错误处理上下文中捕获控制流错误的能力中受益,但不想强制执行特定的样式,那么这是一个不错的选择。
¥This is a good option if you only want to benefit from rule's ability to catch control flow bugs in error-handling contexts, but don't want to enforce a particular style otherwise.
我们建议你配置 in-try-catch
或 always
,而不是此选项。虽然在错误处理上下文之外等待承诺的选 择主要是风格上的,但通常最好保持一致。
¥We recommend you configure either in-try-catch
or always
instead of this option.
While the choice of whether to await promises outside of error-handling contexts is mostly stylistic, it's generally best to be consistent.
此规则使用 error-handling-correctness-only
的其他正确代码示例:
¥Examples of additional correct code with error-handling-correctness-only
:
- ✅ Correct
async function asyncFunction(): Promise<void> {
if (Math.random() < 0.5) {
return await Promise.resolve();
} else {
return Promise.resolve();
}
}
Open in Playgroundnever
不允许等待任何返回的承诺。
¥Disallows awaiting any returned promises.
此选项已弃用,将在 typescript-eslint 的未来主要版本中删除。
¥This option is deprecated and will be removed in a future major version of typescript-eslint.
never
选项在错误处理上下文中引入了不良行为。如果你希望尽量减少返回等待的承诺,请考虑改用 in-try-catch
,这通常也禁止返回等待的承诺,但仅限于不等待承诺是安全的情况下。
¥The never
option introduces undesirable behavior in error-handling contexts.
If you prefer to minimize returning awaited promises, consider instead using in-try-catch
instead, which also generally bans returning awaited promises, but only where it is safe not to await a promise.
有关更多详细信息,请参阅 typescript-eslint#9433。
¥See more details at typescript-eslint#9433.
带有 never
的代码示例:
¥Examples of code with never
:
- ❌ Incorrect
- ✅ Correct
async function invalidNever1() {
try {
return await Promise.resolve('try');
} catch (e) {}
}
async function invalidNever2() {
return await Promise.resolve('try');
}
async function invalidNever3() {
return await 'value';
}
Open in Playgroundasync function validNever1() {
try {
return Promise.resolve('try');
} catch (e) {}
}
async function validNever2() {
return Promise.resolve('try');
}
async function validNever3() {
return 'value';
}
Open in Playground何时不使用它
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.
'## 资源'