Skip to content

Commit 83fdecf

Browse files
committed
Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a function, skip the overload if the parameter has fewer arguments than the argument does. That overload cannot possibly apply, and should not participate in, for example, contextual typing. Example: ```ts interface I { (a: number): void; (b: string, c): void; } declare function f(i: I): void; f((x, y) => {}); ``` This code now skips the first overload instead of considering. This was a longstanding bug but was only uncovered now that more functions expressions are context sensitive.
1 parent f307948 commit 83fdecf

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11890,6 +11890,11 @@ namespace ts {
1189011890
// If the effective argument type is 'undefined', there is no synthetic type
1189111891
// for the argument. In that case, we should check the argument.
1189211892
if (argType === undefined) {
11893+
// If the parameter and argument are both functions and the parameter has fewer arguments than the argument,
11894+
// then this signature is not applicable. Exit early.
11895+
if (!reportErrors && isAritySmaller(paramType, arg)) {
11896+
return false;
11897+
}
1189311898
argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
1189411899
}
1189511900

@@ -11904,6 +11909,21 @@ namespace ts {
1190411909
return true;
1190511910
}
1190611911

11912+
function isAritySmaller(sourceType: Type, target: Expression) {
11913+
if (isFunctionExpressionOrArrowFunction(target) && isFunctionType(sourceType)) {
11914+
let targetParameterCount = 0;
11915+
for (; targetParameterCount < target.parameters.length; targetParameterCount++) {
11916+
const param = target.parameters[targetParameterCount];
11917+
if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) {
11918+
break;
11919+
}
11920+
}
11921+
const sourceSignatures = getSignaturesOfType(sourceType, SignatureKind.Call);
11922+
const sourceLengths = sourceSignatures.map(sig => !sig.hasRestParameter ? sig.parameters.length : Number.MAX_VALUE);
11923+
return forEach(sourceLengths, len => len < targetParameterCount);
11924+
}
11925+
}
11926+
1190711927
/**
1190811928
* Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise.
1190911929
*/

0 commit comments

Comments
 (0)