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.
This commit is contained in:
Nathan Shively-Sanders 2016-10-27 14:41:40 -07:00
parent f307948af0
commit 83fdecf86a

View file

@ -11890,6 +11890,11 @@ namespace ts {
// If the effective argument type is 'undefined', there is no synthetic type
// for the argument. In that case, we should check the argument.
if (argType === undefined) {
// If the parameter and argument are both functions and the parameter has fewer arguments than the argument,
// then this signature is not applicable. Exit early.
if (!reportErrors && isAritySmaller(paramType, arg)) {
return false;
}
argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
}
@ -11904,6 +11909,21 @@ namespace ts {
return true;
}
function isAritySmaller(sourceType: Type, target: Expression) {
if (isFunctionExpressionOrArrowFunction(target) && isFunctionType(sourceType)) {
let targetParameterCount = 0;
for (; targetParameterCount < target.parameters.length; targetParameterCount++) {
const param = target.parameters[targetParameterCount];
if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) {
break;
}
}
const sourceSignatures = getSignaturesOfType(sourceType, SignatureKind.Call);
const sourceLengths = sourceSignatures.map(sig => !sig.hasRestParameter ? sig.parameters.length : Number.MAX_VALUE);
return forEach(sourceLengths, len => len < targetParameterCount);
}
}
/**
* Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise.
*/