From ef83109dbf122644bdba9a8cb97ea007c7668ea0 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Wed, 22 Apr 2020 14:28:11 -0400 Subject: [PATCH] Prefer a likely literal over anonymous type in --noImplicitAny codefixes (#36015) * Prefer a likely literal over anonymous type in --noImplicitAny codefixes Before trying to make an anonymous type for a type's usage, we'll first check if there is exactly one builtin primitive the usage is assignable to, and use it if so. Right now that's only `number` and `string` because `boolean` has no distinguishable members. A couple of implementation details: * `tryInsertTypeAnnotation` needed to know to insert a type _after_ a node's `exclamationToken` if it exists * This code area was written before `??` :wink: * Used unknown/any instead of void when applicable * Fix little whitespace change in tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts * Undid some now-unnecessary unknown additions * Took advice on restricting void to just call expressions --- src/services/codefixes/inferFromUsage.ts | 11 ++++++----- src/services/textChanges.ts | 2 +- .../codeFixInferFromUsageParameterLiteral.ts | 10 ++++++++++ .../fourslash/codeFixInferFromUsagePropertyAccess.ts | 2 +- .../codeFixInferFromUsagePropertyAccessJS.ts | 2 +- .../fourslash/codeFixInferFromUsageVariableLiteral.ts | 9 +++++++++ 6 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 tests/cases/fourslash/codeFixInferFromUsageParameterLiteral.ts create mode 100644 tests/cases/fourslash/codeFixInferFromUsageVariableLiteral.ts diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 0af71bbbb9..7fa01819d2 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -603,7 +603,7 @@ namespace ts.codefix { switch (node.parent.kind) { case SyntaxKind.ExpressionStatement: - addCandidateType(usage, checker.getVoidType()); + inferTypeFromExpressionStatement(node, usage); break; case SyntaxKind.PostfixUnaryExpression: usage.isNumber = true; @@ -661,6 +661,10 @@ namespace ts.codefix { } } + function inferTypeFromExpressionStatement(node: Expression, usage: Usage): void { + addCandidateType(usage, isCallExpression(node) ? checker.getVoidType() : checker.getAnyType()); + } + function inferTypeFromPrefixUnaryExpression(node: PrefixUnaryExpression, usage: Usage): void { switch (node.operator) { case SyntaxKind.PlusPlusToken: @@ -960,10 +964,7 @@ namespace ts.codefix { if (usage.numberIndex) { types.push(checker.createArrayType(combineFromUsage(usage.numberIndex))); } - if (usage.properties && usage.properties.size - || usage.calls && usage.calls.length - || usage.constructs && usage.constructs.length - || usage.stringIndex) { + if (usage.properties?.size || usage.calls?.length || usage.constructs?.length || usage.stringIndex) { types.push(inferStructuralType(usage)); } diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index bf1dae6560..2b743f4d59 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -434,7 +434,7 @@ namespace ts.textChanges { } } else { - endNode = node.kind !== SyntaxKind.VariableDeclaration && node.questionToken ? node.questionToken : node.name; + endNode = (node.kind === SyntaxKind.VariableDeclaration ? node.exclamationToken : node.questionToken) ?? node.name; } this.insertNodeAt(sourceFile, endNode.end, type, { prefix: ": " }); diff --git a/tests/cases/fourslash/codeFixInferFromUsageParameterLiteral.ts b/tests/cases/fourslash/codeFixInferFromUsageParameterLiteral.ts new file mode 100644 index 0000000000..1661063598 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromUsageParameterLiteral.ts @@ -0,0 +1,10 @@ +/// + +// @noImplicitAny: true +//// function foo([|text |]) { +//// text.length; +//// text.indexOf("z"); +//// text.charAt(0); +//// } + +verify.rangeAfterCodeFix("text: string", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); diff --git a/tests/cases/fourslash/codeFixInferFromUsagePropertyAccess.ts b/tests/cases/fourslash/codeFixInferFromUsagePropertyAccess.ts index 44d2e2d7b1..41112b2409 100644 --- a/tests/cases/fourslash/codeFixInferFromUsagePropertyAccess.ts +++ b/tests/cases/fourslash/codeFixInferFromUsagePropertyAccess.ts @@ -12,4 +12,4 @@ //// return x.y.z ////} -verify.rangeAfterCodeFix("a: { b: { c: void; }; }, m: { n: () => number; }, x: { y: { z: number[]; }; }", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); +verify.rangeAfterCodeFix("a: { b: { c: any; }; }, m: { n: () => number; }, x: { y: { z: number[]; }; }", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); diff --git a/tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts b/tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts index 357b1a991b..ed9d4b33b3 100644 --- a/tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts +++ b/tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts @@ -21,7 +21,7 @@ verify.codeFix({ index: 0, newFileContent: `/** - * @param {{ b: { c: void; }; }} a + * @param {{ b: { c: any; }; }} a * @param {{ n: () => number; }} m * @param {{ y: { z: number[]; }; }} x */ diff --git a/tests/cases/fourslash/codeFixInferFromUsageVariableLiteral.ts b/tests/cases/fourslash/codeFixInferFromUsageVariableLiteral.ts new file mode 100644 index 0000000000..2641b00963 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromUsageVariableLiteral.ts @@ -0,0 +1,9 @@ +/// + +// @noImplicitAny: true +//// let [|text! |]; +//// text.length; +//// text.indexOf("z"); +//// text.charAt(0); + +verify.rangeAfterCodeFix("text!: string", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0);