mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Add quick fix to add 'void' to Promise resolved without value (#40558)
* Add codefix to add 'void' to Promise resolved without value * Add specific error message in checker to reduce quick-fix time in editor
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
const fixName = "addVoidToPromise";
|
||||
const fixId = "addVoidToPromise";
|
||||
const errorCodes = [
|
||||
Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise.code
|
||||
];
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
fixIds: [fixId],
|
||||
getCodeActions(context) {
|
||||
const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span, context.program));
|
||||
if (changes.length > 0) {
|
||||
return [createCodeFixAction(fixName, changes, Diagnostics.Add_void_to_Promise_resolved_without_a_value, fixId, Diagnostics.Add_void_to_all_Promises_resolved_without_a_value)];
|
||||
}
|
||||
},
|
||||
getAllCodeActions(context: CodeFixAllContext) {
|
||||
return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag, context.program, new Set()));
|
||||
}
|
||||
});
|
||||
|
||||
function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan, program: Program, seen?: Set<ParameterDeclaration>) {
|
||||
const node = getTokenAtPosition(sourceFile, span.start);
|
||||
if (!isIdentifier(node) || !isCallExpression(node.parent) || node.parent.expression !== node || node.parent.arguments.length !== 0) return;
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const symbol = checker.getSymbolAtLocation(node);
|
||||
|
||||
// decl should be `new Promise((<decl>) => {})`
|
||||
const decl = symbol?.valueDeclaration;
|
||||
if (!decl || !isParameter(decl) || !isNewExpression(decl.parent.parent)) return;
|
||||
|
||||
// no need to make this change if we have already seen this parameter.
|
||||
if (seen?.has(decl)) return;
|
||||
seen?.add(decl);
|
||||
|
||||
const typeArguments = getEffectiveTypeArguments(decl.parent.parent);
|
||||
if (some(typeArguments)) {
|
||||
// append ` | void` to type argument
|
||||
const typeArgument = typeArguments[0];
|
||||
const needsParens = !isUnionTypeNode(typeArgument) && !isParenthesizedTypeNode(typeArgument) &&
|
||||
isParenthesizedTypeNode(factory.createUnionTypeNode([typeArgument, factory.createKeywordTypeNode(SyntaxKind.VoidKeyword)]).types[0]);
|
||||
if (needsParens) {
|
||||
changes.insertText(sourceFile, typeArgument.pos, "(");
|
||||
}
|
||||
changes.insertText(sourceFile, typeArgument.end, needsParens ? ") | void" : " | void");
|
||||
}
|
||||
else {
|
||||
// make sure the Promise is type is untyped (i.e., `unknown`)
|
||||
const signature = checker.getResolvedSignature(node.parent);
|
||||
const parameter = signature?.parameters[0];
|
||||
const parameterType = parameter && checker.getTypeOfSymbolAtLocation(parameter, decl.parent.parent);
|
||||
if (isInJSFile(decl)) {
|
||||
if (!parameterType || parameterType.flags & TypeFlags.AnyOrUnknown) {
|
||||
// give the expression a type
|
||||
changes.insertText(sourceFile, decl.parent.parent.end, `)`);
|
||||
changes.insertText(sourceFile, skipTrivia(sourceFile.text, decl.parent.parent.pos), `/** @type {Promise<void>} */(`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!parameterType || parameterType.flags & TypeFlags.Unknown) {
|
||||
// add `void` type argument
|
||||
changes.insertText(sourceFile, decl.parent.parent.expression.end, "<void>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEffectiveTypeArguments(node: NewExpression) {
|
||||
if (isInJSFile(node)) {
|
||||
if (isParenthesizedExpression(node.parent)) {
|
||||
const jsDocType = getJSDocTypeTag(node.parent)?.typeExpression.type;
|
||||
if (jsDocType && isTypeReferenceNode(jsDocType) && isIdentifier(jsDocType.typeName) && idText(jsDocType.typeName) === "Promise") {
|
||||
return jsDocType.typeArguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return node.typeArguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,6 +107,7 @@
|
||||
"codefixes/splitTypeOnlyImport.ts",
|
||||
"codefixes/convertConstToLet.ts",
|
||||
"codefixes/fixExpectedComma.ts",
|
||||
"codefixes/fixAddVoidToPromise.ts",
|
||||
"refactors/convertExport.ts",
|
||||
"refactors/convertImport.ts",
|
||||
"refactors/convertToOptionalChainExpression.ts",
|
||||
|
||||
Reference in New Issue
Block a user