mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-23 18:48:40 -05:00
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.
This commit is contained in:
committed by
GitHub
parent
2103ed69e6
commit
594430f113
@@ -187,24 +187,10 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function isApplicableFunctionForInference(declaration: FunctionLike): declaration is MethodDeclaration | FunctionDeclaration | ConstructorDeclaration {
|
||||
switch (declaration.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.Constructor:
|
||||
return true;
|
||||
case SyntaxKind.FunctionExpression:
|
||||
const parent = declaration.parent;
|
||||
return isVariableDeclaration(parent) && isIdentifier(parent.name) || !!declaration.name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function annotateParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parameterDeclaration: ParameterDeclaration, containingFunction: FunctionLike, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
|
||||
if (!isIdentifier(parameterDeclaration.name) || !isApplicableFunctionForInference(containingFunction)) {
|
||||
if (!isIdentifier(parameterDeclaration.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parameterInferences = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
|
||||
containingFunction.parameters.map<ParameterInference>(p => ({
|
||||
declaration: p,
|
||||
@@ -216,11 +202,14 @@ namespace ts.codefix {
|
||||
annotateJSDocParameters(changes, sourceFile, parameterInferences, program, host);
|
||||
}
|
||||
else {
|
||||
const needParens = isArrowFunction(containingFunction) && !findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile);
|
||||
if (needParens) changes.insertNodeBefore(sourceFile, first(containingFunction.parameters), createToken(SyntaxKind.OpenParenToken));
|
||||
for (const { declaration, type } of parameterInferences) {
|
||||
if (declaration && !declaration.type && !declaration.initializer) {
|
||||
annotate(changes, sourceFile, declaration, type, program, host);
|
||||
}
|
||||
}
|
||||
if (needParens) changes.insertNodeAfter(sourceFile, last(containingFunction.parameters), createToken(SyntaxKind.CloseParenToken));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,12 +331,13 @@ namespace ts.codefix {
|
||||
return InferFromReference.unifyFromContext(types, checker);
|
||||
}
|
||||
|
||||
function inferTypeForParametersFromUsage(containingFunction: FunctionLikeDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
function inferTypeForParametersFromUsage(containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
let searchToken;
|
||||
switch (containingFunction.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
searchToken = findChildOfKind<Token<SyntaxKind.ConstructorKeyword>>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile);
|
||||
break;
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
const parent = containingFunction.parent;
|
||||
searchToken = isVariableDeclaration(parent) && isIdentifier(parent.name) ?
|
||||
@@ -399,7 +389,7 @@ namespace ts.codefix {
|
||||
return inferFromContext(usageContext, checker);
|
||||
}
|
||||
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLike, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
const checker = program.getTypeChecker();
|
||||
if (references.length === 0) {
|
||||
return undefined;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
////var f = (x) => x
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: "Annotate with type from JSDoc",
|
||||
newFileContent:
|
||||
`/**
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
////var x = (x, ys, ...zs) => { x; ys; zs; };
|
||||
|
||||
verify.codeFix({
|
||||
index: 3,
|
||||
description: "Annotate with type from JSDoc",
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/** @type {function(*, ...number, ...boolean): void} */
|
||||
var x: (arg0: any, arg1: number[], ...rest: boolean[]) => void = (x, ys, ...zs) => { x; ys; zs; };`,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
////var f = /*a*/x/*b*/ => x
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: "Annotate with type from JSDoc",
|
||||
newFileContent:
|
||||
`/**
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
////var f = x => x
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: "Annotate with type from JSDoc",
|
||||
newFileContent:
|
||||
`/**
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
////}
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: "Add async modifier to containing function",
|
||||
newFileContent:
|
||||
`const f = async promise => {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
////}
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: "Add async modifier to containing function",
|
||||
newFileContent:
|
||||
`const f = async (promise) => {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
////class C implements I<number> {}
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: "Implement interface 'I<number>'",
|
||||
newFileContent:
|
||||
`interface I<Species> {
|
||||
|
||||
15
tests/cases/fourslash/codeFixInferFromUsageArrow.ts
Normal file
15
tests/cases/fourslash/codeFixInferFromUsageArrow.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
////const a = (x) => x;
|
||||
////const b = x => x;
|
||||
////const c = x => x + 1;
|
||||
////const d = x => x;
|
||||
////d(1);
|
||||
verify.codeFixAll({
|
||||
fixId: "inferFromUsage",
|
||||
fixAllDescription: "Infer all types from usage",
|
||||
newFileContent: `const a = (x: any) => x;
|
||||
const b = (x: any) => x;
|
||||
const c = (x: number) => x + 1;
|
||||
const d = (x: number) => x;
|
||||
d(1);`,
|
||||
});
|
||||
Reference in New Issue
Block a user