Skip to content

Commit 594430f

Browse files
authored
Infer from arrows from usage. (#28832)
* Infer from arrows from usage. Previously only function expressions were, and only those with an easily accessible name. Now any arrow function or function expression will infer from usage. * remove isApplicableFunctionForInference *all* functions are applicable for inference now.
1 parent 2103ed6 commit 594430f

9 files changed

+29
-18
lines changed

src/services/codefixes/inferFromUsage.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -187,24 +187,10 @@ namespace ts.codefix {
187187
}
188188
}
189189

190-
function isApplicableFunctionForInference(declaration: FunctionLike): declaration is MethodDeclaration | FunctionDeclaration | ConstructorDeclaration {
191-
switch (declaration.kind) {
192-
case SyntaxKind.FunctionDeclaration:
193-
case SyntaxKind.MethodDeclaration:
194-
case SyntaxKind.Constructor:
195-
return true;
196-
case SyntaxKind.FunctionExpression:
197-
const parent = declaration.parent;
198-
return isVariableDeclaration(parent) && isIdentifier(parent.name) || !!declaration.name;
199-
}
200-
return false;
201-
}
202-
203190
function annotateParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parameterDeclaration: ParameterDeclaration, containingFunction: FunctionLike, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
204-
if (!isIdentifier(parameterDeclaration.name) || !isApplicableFunctionForInference(containingFunction)) {
191+
if (!isIdentifier(parameterDeclaration.name)) {
205192
return;
206193
}
207-
208194
const parameterInferences = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
209195
containingFunction.parameters.map<ParameterInference>(p => ({
210196
declaration: p,
@@ -216,11 +202,14 @@ namespace ts.codefix {
216202
annotateJSDocParameters(changes, sourceFile, parameterInferences, program, host);
217203
}
218204
else {
205+
const needParens = isArrowFunction(containingFunction) && !findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile);
206+
if (needParens) changes.insertNodeBefore(sourceFile, first(containingFunction.parameters), createToken(SyntaxKind.OpenParenToken));
219207
for (const { declaration, type } of parameterInferences) {
220208
if (declaration && !declaration.type && !declaration.initializer) {
221209
annotate(changes, sourceFile, declaration, type, program, host);
222210
}
223211
}
212+
if (needParens) changes.insertNodeAfter(sourceFile, last(containingFunction.parameters), createToken(SyntaxKind.CloseParenToken));
224213
}
225214
}
226215

@@ -342,12 +331,13 @@ namespace ts.codefix {
342331
return InferFromReference.unifyFromContext(types, checker);
343332
}
344333

345-
function inferTypeForParametersFromUsage(containingFunction: FunctionLikeDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
334+
function inferTypeForParametersFromUsage(containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
346335
let searchToken;
347336
switch (containingFunction.kind) {
348337
case SyntaxKind.Constructor:
349338
searchToken = findChildOfKind<Token<SyntaxKind.ConstructorKeyword>>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile);
350339
break;
340+
case SyntaxKind.ArrowFunction:
351341
case SyntaxKind.FunctionExpression:
352342
const parent = containingFunction.parent;
353343
searchToken = isVariableDeclaration(parent) && isIdentifier(parent.name) ?
@@ -399,7 +389,7 @@ namespace ts.codefix {
399389
return inferFromContext(usageContext, checker);
400390
}
401391

402-
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
392+
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLike, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
403393
const checker = program.getTypeChecker();
404394
if (references.length === 0) {
405395
return undefined;

tests/cases/fourslash/annotateWithTypeFromJSDoc11.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
////var f = (x) => x
88

99
verify.codeFix({
10+
index: 0,
1011
description: "Annotate with type from JSDoc",
1112
newFileContent:
1213
`/**

tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
////var x = (x, ys, ...zs) => { x; ys; zs; };
55

66
verify.codeFix({
7+
index: 3,
78
description: "Annotate with type from JSDoc",
8-
index: 0,
99
newFileContent:
1010
`/** @type {function(*, ...number, ...boolean): void} */
1111
var x: (arg0: any, arg1: number[], ...rest: boolean[]) => void = (x, ys, ...zs) => { x; ys; zs; };`,

tests/cases/fourslash/annotateWithTypeFromJSDoc9.5.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
////var f = /*a*/x/*b*/ => x
99

1010
verify.codeFix({
11+
index: 0,
1112
description: "Annotate with type from JSDoc",
1213
newFileContent:
1314
`/**

tests/cases/fourslash/annotateWithTypeFromJSDoc9.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
////var f = x => x
88

99
verify.codeFix({
10+
index: 0,
1011
description: "Annotate with type from JSDoc",
1112
newFileContent:
1213
`/**

tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
////}
66

77
verify.codeFix({
8+
index: 0,
89
description: "Add async modifier to containing function",
910
newFileContent:
1011
`const f = async promise => {

tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
////}
66

77
verify.codeFix({
8+
index: 0,
89
description: "Add async modifier to containing function",
910
newFileContent:
1011
`const f = async (promise) => {

tests/cases/fourslash/codeFixClassImplementInterfaceComputedPropertyNameWellKnownSymbols.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
////class C implements I<number> {}
2121

2222
verify.codeFix({
23+
index: 0,
2324
description: "Implement interface 'I<number>'",
2425
newFileContent:
2526
`interface I<Species> {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path='fourslash.ts' />
2+
////const a = (x) => x;
3+
////const b = x => x;
4+
////const c = x => x + 1;
5+
////const d = x => x;
6+
////d(1);
7+
verify.codeFixAll({
8+
fixId: "inferFromUsage",
9+
fixAllDescription: "Infer all types from usage",
10+
newFileContent: `const a = (x: any) => x;
11+
const b = (x: any) => x;
12+
const c = (x: number) => x + 1;
13+
const d = (x: number) => x;
14+
d(1);`,
15+
});

0 commit comments

Comments
 (0)