Skip to content

Commit 89badcc

Browse files
authored
Add 'Remove unnecessary await' suggestion and fix (#32363)
* Add remove unnecessary await fix * Add test for removing unnecessary parens after await is gone * Fix handling of numbers in property access expressions * Don’t offer suggestion when awaited type is any/unknown * Fix random other test * Fix new expression edge cases * Only remove parens for identifiers and call expressions
1 parent 60a1b1d commit 89badcc

File tree

6 files changed

+97
-5
lines changed

6 files changed

+97
-5
lines changed

src/compiler/checker.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -26403,7 +26403,11 @@ namespace ts {
2640326403
* The runtime behavior of the `await` keyword.
2640426404
*/
2640526405
function checkAwaitedType(type: Type, errorNode: Node, diagnosticMessage: DiagnosticMessage, arg0?: string | number): Type {
26406-
return getAwaitedType(type, errorNode, diagnosticMessage, arg0) || errorType;
26406+
const awaitedType = getAwaitedType(type, errorNode, diagnosticMessage, arg0);
26407+
if (awaitedType === type && !(type.flags & TypeFlags.AnyOrUnknown)) {
26408+
addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(errorNode, Diagnostics.await_has_no_effect_on_the_type_of_this_expression));
26409+
}
26410+
return awaitedType || errorType;
2640726411
}
2640826412

2640926413
function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined {

src/compiler/diagnosticMessages.json

+13
Original file line numberDiff line numberDiff line change
@@ -4635,6 +4635,11 @@
46354635
"category": "Suggestion",
46364636
"code": 80006
46374637
},
4638+
"'await' has no effect on the type of this expression.": {
4639+
"category": "Suggestion",
4640+
"code": 80007
4641+
},
4642+
46384643
"Add missing 'super()' call": {
46394644
"category": "Message",
46404645
"code": 90001
@@ -5095,6 +5100,14 @@
50955100
"category": "Message",
50965101
"code": 95085
50975102
},
5103+
"Remove unnecessary 'await'": {
5104+
"category": "Message",
5105+
"code": 95086
5106+
},
5107+
"Remove all unnecessary uses of 'await'": {
5108+
"category": "Message",
5109+
"code": 95087
5110+
},
50985111

50995112
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
51005113
"category": "Error",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* @internal */
2+
namespace ts.codefix {
3+
const fixId = "removeUnnecessaryAwait";
4+
const errorCodes = [
5+
Diagnostics.await_has_no_effect_on_the_type_of_this_expression.code,
6+
];
7+
8+
registerCodeFix({
9+
errorCodes,
10+
getCodeActions: (context) => {
11+
const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span));
12+
if (changes.length > 0) {
13+
return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unnecessary_await, fixId, Diagnostics.Remove_all_unnecessary_uses_of_await)];
14+
}
15+
},
16+
fixIds: [fixId],
17+
getAllCodeActions: context => {
18+
return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag));
19+
},
20+
});
21+
22+
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan) {
23+
const awaitKeyword = tryCast(getTokenAtPosition(sourceFile, span.start), (node): node is AwaitKeywordToken => node.kind === SyntaxKind.AwaitKeyword);
24+
const awaitExpression = awaitKeyword && tryCast(awaitKeyword.parent, isAwaitExpression);
25+
if (!awaitExpression) {
26+
return;
27+
}
28+
29+
const parenthesizedExpression = tryCast(awaitExpression.parent, isParenthesizedExpression);
30+
const removeParens = parenthesizedExpression && (isIdentifier(awaitExpression.expression) || isCallExpression(awaitExpression.expression));
31+
changeTracker.replaceNode(sourceFile, removeParens ? parenthesizedExpression || awaitExpression : awaitExpression, awaitExpression.expression);
32+
}
33+
}

src/services/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"codefixes/useDefaultImport.ts",
8181
"codefixes/fixAddModuleReferTypeMissingTypeof.ts",
8282
"codefixes/convertToMappedObjectType.ts",
83+
"codefixes/removeUnnecessaryAwait.ts",
8384
"refactors/convertExport.ts",
8485
"refactors/convertImport.ts",
8586
"refactors/extractSymbol.ts",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/// <reference path="fourslash.ts" />
2+
////declare class C { foo(): void }
3+
////declare function foo(): string;
4+
////async function f() {
5+
//// await "";
6+
//// await 0;
7+
//// (await foo()).toLowerCase();
8+
//// (await 0).toFixed();
9+
//// (await new C).foo();
10+
////}
11+
12+
verify.codeFix({
13+
description: ts.Diagnostics.Remove_unnecessary_await.message,
14+
index: 0,
15+
newFileContent:
16+
`declare class C { foo(): void }
17+
declare function foo(): string;
18+
async function f() {
19+
"";
20+
await 0;
21+
(await foo()).toLowerCase();
22+
(await 0).toFixed();
23+
(await new C).foo();
24+
}`
25+
});
26+
27+
verify.codeFixAll({
28+
fixAllDescription: ts.Diagnostics.Remove_all_unnecessary_uses_of_await.message,
29+
fixId: "removeUnnecessaryAwait",
30+
newFileContent:
31+
`declare class C { foo(): void }
32+
declare function foo(): string;
33+
async function f() {
34+
"";
35+
0;
36+
foo().toLowerCase();
37+
(0).toFixed();
38+
(new C).foo();
39+
}`
40+
});

tests/cases/fourslash/convertFunctionToEs6Class_asyncMethods.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
// @allowNonTsExtensions: true
44
// @Filename: test123.js
5+
// @lib: es5
56
////export function /**/MyClass() {
67
////}
78
////MyClass.prototype.foo = async function() {
8-
//// await 2;
9+
//// await Promise.resolve();
910
////}
1011
////MyClass.bar = async function() {
11-
//// await 3;
12+
//// await Promise.resolve();
1213
////}
1314

1415
verify.codeFix({
@@ -18,10 +19,10 @@ verify.codeFix({
1819
constructor() {
1920
}
2021
async foo() {
21-
await 2;
22+
await Promise.resolve();
2223
}
2324
static async bar() {
24-
await 3;
25+
await Promise.resolve();
2526
}
2627
}
2728
`,

0 commit comments

Comments
 (0)