mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Add elaboration & quickfix for async-able arrow function (#36342)
This commit is contained in:
parent
6b645f582b
commit
ebca423a6e
@ -14153,6 +14153,17 @@ namespace ts {
|
||||
Diagnostics.The_expected_type_comes_from_the_return_type_of_this_signature,
|
||||
));
|
||||
}
|
||||
if ((getFunctionFlags(node) & FunctionFlags.Async) === 0
|
||||
// exclude cases where source itself is promisy - this way we don't make a suggestion when relating
|
||||
// an IPromise and a Promise that are slightly different
|
||||
&& !getTypeOfPropertyOfType(sourceReturn, "then" as __String)
|
||||
&& checkTypeRelatedTo(createPromiseType(sourceReturn), targetReturn, relation, /*errorNode*/ undefined)
|
||||
) {
|
||||
addRelatedInfo(resultObj.errors[resultObj.errors.length - 1], createDiagnosticForNode(
|
||||
node,
|
||||
Diagnostics.Did_you_mean_to_mark_this_function_as_async
|
||||
));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
87
src/services/codefixes/addMissingAsync.ts
Normal file
87
src/services/codefixes/addMissingAsync.ts
Normal file
@ -0,0 +1,87 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
type ContextualTrackChangesFunction = (cb: (changeTracker: textChanges.ChangeTracker) => void) => FileTextChanges[];
|
||||
const fixId = "addMissingAsync";
|
||||
const errorCodes = [
|
||||
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code,
|
||||
Diagnostics.Type_0_is_not_assignable_to_type_1.code,
|
||||
Diagnostics.Type_0_is_not_comparable_to_type_1.code
|
||||
];
|
||||
|
||||
registerCodeFix({
|
||||
fixIds: [fixId],
|
||||
errorCodes,
|
||||
getCodeActions: context => {
|
||||
const { sourceFile, errorCode, cancellationToken, program, span } = context;
|
||||
const diagnostic = find(program.getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile, cancellationToken), getIsMatchingAsyncError(span, errorCode));
|
||||
const directSpan = diagnostic && diagnostic.relatedInformation && find(diagnostic.relatedInformation, r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code) as TextSpan | undefined;
|
||||
|
||||
const decl = getFixableErrorSpanDeclaration(sourceFile, directSpan);
|
||||
if (!decl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const trackChanges: ContextualTrackChangesFunction = cb => textChanges.ChangeTracker.with(context, cb);
|
||||
return [getFix(context, decl, trackChanges)];
|
||||
},
|
||||
getAllCodeActions: context => {
|
||||
const { sourceFile } = context;
|
||||
const fixedDeclarations = createMap<true>();
|
||||
return codeFixAll(context, errorCodes, (t, diagnostic) => {
|
||||
const span = diagnostic.relatedInformation && find(diagnostic.relatedInformation, r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code) as TextSpan | undefined;
|
||||
const decl = getFixableErrorSpanDeclaration(sourceFile, span);
|
||||
if (!decl) {
|
||||
return;
|
||||
}
|
||||
const trackChanges: ContextualTrackChangesFunction = cb => (cb(t), []);
|
||||
return getFix(context, decl, trackChanges, fixedDeclarations);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
type FixableDeclaration = ArrowFunction | FunctionDeclaration | FunctionExpression | MethodDeclaration;
|
||||
function getFix(context: CodeFixContext | CodeFixAllContext, decl: FixableDeclaration, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Map<true>) {
|
||||
const changes = trackChanges(t => makeChange(t, context.sourceFile, decl, fixedDeclarations));
|
||||
return createCodeFixAction(fixId, changes, Diagnostics.Add_async_modifier_to_containing_function, fixId, Diagnostics.Add_all_missing_async_modifiers);
|
||||
}
|
||||
|
||||
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, insertionSite: FixableDeclaration, fixedDeclarations?: Map<true>) {
|
||||
if (fixedDeclarations) {
|
||||
if (fixedDeclarations.has(getNodeId(insertionSite).toString())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
fixedDeclarations?.set(getNodeId(insertionSite).toString(), true);
|
||||
const cloneWithModifier = getSynthesizedDeepClone(insertionSite, /*includeTrivia*/ true);
|
||||
cloneWithModifier.modifiers = createNodeArray(createModifiersFromModifierFlags(getModifierFlags(insertionSite) | ModifierFlags.Async));
|
||||
cloneWithModifier.modifierFlagsCache = 0;
|
||||
changeTracker.replaceNode(
|
||||
sourceFile,
|
||||
insertionSite,
|
||||
cloneWithModifier);
|
||||
}
|
||||
|
||||
function getFixableErrorSpanDeclaration(sourceFile: SourceFile, span: TextSpan | undefined): FixableDeclaration | undefined {
|
||||
if (!span) return undefined;
|
||||
const token = getTokenAtPosition(sourceFile, span.start);
|
||||
// Checker has already done work to determine that async might be possible, and has attached
|
||||
// related info to the node, so start by finding the signature that exactly matches up
|
||||
// with the diagnostic range.
|
||||
const decl = findAncestor(token, node => {
|
||||
if (node.getStart(sourceFile) < span.start || node.getEnd() > textSpanEnd(span)) {
|
||||
return "quit";
|
||||
}
|
||||
return (isArrowFunction(node) || isMethodDeclaration(node) || isFunctionExpression(node) || isFunctionDeclaration(node)) && textSpansEqual(span, createTextSpanFromNode(node, sourceFile));
|
||||
}) as FixableDeclaration | undefined;
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
function getIsMatchingAsyncError(span: TextSpan, errorCode: number) {
|
||||
return ({ start, length, relatedInformation, code }: Diagnostic) =>
|
||||
isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) &&
|
||||
code === errorCode &&
|
||||
!!relatedInformation &&
|
||||
some(relatedInformation, related => related.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code);
|
||||
}
|
||||
}
|
||||
@ -48,6 +48,7 @@
|
||||
"refactorProvider.ts",
|
||||
"codefixes/addConvertToUnknownForNonOverlappingTypes.ts",
|
||||
"codefixes/addEmptyExportDeclaration.ts",
|
||||
"codefixes/addMissingAsync.ts",
|
||||
"codefixes/addMissingAwait.ts",
|
||||
"codefixes/addMissingConst.ts",
|
||||
"codefixes/addMissingDeclareProperty.ts",
|
||||
|
||||
@ -37,41 +37,51 @@ tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts(27,16): err
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:3:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:18:10: Did you mean to mark this function as 'async'?
|
||||
c: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:4:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:19:10: Did you mean to mark this function as 'async'?
|
||||
d: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:5:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:20:10: Did you mean to mark this function as 'async'?
|
||||
e: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:6:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:21:10: Did you mean to mark this function as 'async'?
|
||||
f: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:7:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:22:10: Did you mean to mark this function as 'async'?
|
||||
g: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:8:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:23:10: Did you mean to mark this function as 'async'?
|
||||
h: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:9:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:24:10: Did you mean to mark this function as 'async'?
|
||||
i: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:10:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:25:10: Did you mean to mark this function as 'async'?
|
||||
j: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:11:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:26:10: Did you mean to mark this function as 'async'?
|
||||
k: () => 123
|
||||
~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'Promise<number>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:12:8: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate.ts:27:10: Did you mean to mark this function as 'async'?
|
||||
}
|
||||
}
|
||||
@ -37,41 +37,51 @@ tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts(27,14): er
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:3:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:18:8: Did you mean to mark this function as 'async'?
|
||||
c: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:4:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:19:8: Did you mean to mark this function as 'async'?
|
||||
d: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:5:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:20:8: Did you mean to mark this function as 'async'?
|
||||
e: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:6:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:21:8: Did you mean to mark this function as 'async'?
|
||||
f: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:7:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:22:8: Did you mean to mark this function as 'async'?
|
||||
g: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:8:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:23:8: Did you mean to mark this function as 'async'?
|
||||
h: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:9:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:24:8: Did you mean to mark this function as 'async'?
|
||||
i: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:10:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:25:8: Did you mean to mark this function as 'async'?
|
||||
j: () => "hello",
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:11:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:26:8: Did you mean to mark this function as 'async'?
|
||||
k: () => 123
|
||||
~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'Promise<number>'.
|
||||
!!! related TS6502 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:12:6: The expected type comes from the return type of this signature.
|
||||
!!! related TS1356 tests/cases/compiler/errorOnUnionVsObjectShouldDeeplyDisambiguate2.ts:27:8: Did you mean to mark this function as 'async'?
|
||||
}
|
||||
}
|
||||
26
tests/cases/fourslash/codeFixAddMissingAsync.ts
Normal file
26
tests/cases/fourslash/codeFixAddMissingAsync.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
////interface Stuff {
|
||||
//// b: () => Promise<string>;
|
||||
////}
|
||||
////
|
||||
////function foo(): Stuff | Date {
|
||||
//// return {
|
||||
//// b: () => "hello",
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_async_modifier_to_containing_function.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface Stuff {
|
||||
b: () => Promise<string>;
|
||||
}
|
||||
|
||||
function foo(): Stuff | Date {
|
||||
return {
|
||||
b: async () => "hello",
|
||||
}
|
||||
}`
|
||||
});
|
||||
|
||||
26
tests/cases/fourslash/codeFixAddMissingAsync2.ts
Normal file
26
tests/cases/fourslash/codeFixAddMissingAsync2.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
////interface Stuff {
|
||||
//// b: () => Promise<string>;
|
||||
////}
|
||||
////
|
||||
////function foo(): Stuff | Date {
|
||||
//// return {
|
||||
//// b: _ => "hello",
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_async_modifier_to_containing_function.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface Stuff {
|
||||
b: () => Promise<string>;
|
||||
}
|
||||
|
||||
function foo(): Stuff | Date {
|
||||
return {
|
||||
b: async (_) => "hello",
|
||||
}
|
||||
}`
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user