Bad callsite inferences fall back to body usage (#28235)

For parameters, the infer-from-usage codefix uses a substantially
different codepath that previously only looked at call site uses. When
this resulted in no inferences, or bad inferences, for a single
parameter, the codefix would just use any. Only if no usages of a
function were found would the codefix use the body-inference
code.

This commit makes parameter inference fall back to body-inference code
for individual parameters when there is no inference or inference to
any.
This commit is contained in:
Nathan Shively-Sanders
2018-10-30 13:25:24 -07:00
committed by GitHub
parent 437bc41e99
commit 0481d44501
2 changed files with 28 additions and 5 deletions

View File

@@ -349,7 +349,7 @@ namespace ts.codefix {
findChildOfKind<Token<SyntaxKind.ConstructorKeyword>>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile) :
containingFunction.name;
if (searchToken) {
return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program.getTypeChecker(), cancellationToken);
return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program, cancellationToken);
}
}
}
@@ -387,7 +387,8 @@ namespace ts.codefix {
return getTypeFromUsageContext(usageContext, checker) || checker.getAnyType();
}
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, checker: TypeChecker, cancellationToken: CancellationToken): ParameterInference[] | undefined {
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
const checker = program.getTypeChecker();
if (references.length === 0) {
return undefined;
}
@@ -422,10 +423,14 @@ namespace ts.codefix {
types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex]));
}
}
if (!types.length) {
return { declaration: parameter, type: checker.getAnyType() };
let type = types.length && checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype));
if ((!type || type.flags & TypeFlags.Any) && isIdentifier(parameter.name)) {
type = inferTypeForVariableFromUsage(parameter.name, program, cancellationToken);
}
if (!type) {
type = checker.getAnyType();
}
const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype));
return {
type: isRest ? checker.createArrayType(type) : type,
isOptional: isOptional && !isRest,