feat(36266): add a quick fix for incorrect return types in async functions

This commit is contained in:
Alexander T
2020-04-10 14:19:39 +03:00
committed by Eli Barzilay
parent ca234d2b60
commit 0503da225d
28 changed files with 329 additions and 16 deletions

View File

@@ -406,6 +406,7 @@ namespace ts {
},
getParameterType: getTypeAtPosition,
getPromisedTypeOfPromise,
getAwaitedType: type => getAwaitedType(type),
getReturnTypeOfSignature,
isNullableType,
getNullableType,
@@ -30795,7 +30796,7 @@ namespace ts {
if (globalPromiseType !== emptyGenericType && !isReferenceToType(returnType, globalPromiseType)) {
// The promise type was not a valid type reference to the global promise type, so we
// report an error and return the unknown type.
error(returnTypeNode, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type);
error(returnTypeNode, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, typeToString(getAwaitedType(returnType) || voidType));
return;
}
}

View File

@@ -215,7 +215,7 @@
"category": "Error",
"code": 1063
},
"The return type of an async function or method must be the global Promise<T> type.": {
"The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<{0}>'?": {
"category": "Error",
"code": 1064
},
@@ -5197,6 +5197,14 @@
"category": "Message",
"code": 90035
},
"Replace '{0}' with 'Promise<{1}>'": {
"category": "Message",
"code": 90036
},
"Fix all incorrect return type of an async functions": {
"category": "Message",
"code": 90037
},
"Declare a private field named '{0}'.": {
"category": "Message",
"code": 90053

View File

@@ -3421,6 +3421,7 @@ namespace ts {
getWidenedType(type: Type): Type;
/* @internal */
getPromisedTypeOfPromise(promise: Type, errorNode?: Node): Type | undefined;
getAwaitedType(type: Type): Type | undefined;
getReturnTypeOfSignature(signature: Signature): Type;
/**
* Gets the type of a parameter at a given position in a signature.

View File

@@ -0,0 +1,66 @@
/* @internal */
namespace ts.codefix {
const fixId = "fixReturnTypeInAsyncFunction";
const errorCodes = [
Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0.code,
];
interface Info {
readonly returnTypeNode: TypeNode;
readonly returnType: Type;
readonly promisedTypeNode: TypeNode;
readonly promisedType: Type;
}
registerCodeFix({
errorCodes,
fixIds: [fixId],
getCodeActions: context => {
const { sourceFile, program, span } = context;
const checker = program.getTypeChecker();
const info = getInfo(sourceFile, program.getTypeChecker(), span.start);
if (!info) {
return undefined;
}
const { returnTypeNode, returnType, promisedTypeNode, promisedType } = info;
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, returnTypeNode, promisedTypeNode));
return [createCodeFixAction(fixId, changes, [Diagnostics.Replace_0_with_Promise_1, checker.typeToString(returnType), checker.typeToString(promisedType)], fixId, Diagnostics.Fix_all_incorrect_return_type_of_an_async_functions)];
},
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const info = getInfo(diag.file, context.program.getTypeChecker(), diag.start);
if (info) {
doChange(changes, diag.file, info.returnTypeNode, info.promisedTypeNode);
}
})
});
function getInfo(sourceFile: SourceFile, checker: TypeChecker, pos: number): Info | undefined {
const returnTypeNode = getReturnTypeNode(sourceFile, pos);
if (!returnTypeNode) {
return undefined;
}
const returnType = checker.getTypeFromTypeNode(returnTypeNode);
const promisedType = checker.getAwaitedType(returnType) || checker.getVoidType();
const promisedTypeNode = checker.typeToTypeNode(promisedType);
if (promisedTypeNode) {
return { returnTypeNode, returnType, promisedTypeNode, promisedType };
}
}
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, returnTypeNode: TypeNode, promisedTypeNode: TypeNode): void {
changes.replaceNode(sourceFile, returnTypeNode, createTypeReferenceNode("Promise", [promisedTypeNode]));
}
function getReturnTypeNode(sourceFile: SourceFile, pos: number): TypeNode | undefined {
if (isInJSFile(sourceFile)) {
return undefined;
}
const token = getTokenAtPosition(sourceFile, pos);
const parent = findAncestor(token, isFunctionLikeDeclaration);
if (parent?.type) {
return parent.type;
}
}
}

View File

@@ -85,6 +85,7 @@
"codefixes/fixMissingCallParentheses.ts",
"codefixes/fixAwaitInSyncFunction.ts",
"codefixes/inferFromUsage.ts",
"codefixes/fixReturnTypeInAsyncFunction.ts",
"codefixes/disableJsDiagnostics.ts",
"codefixes/helpers.ts",
"codefixes/fixInvalidImportSyntax.ts",