mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 20:25:23 -06:00
Do not use contextual signatures with too few parameters
This commit is contained in:
parent
4e57f700d0
commit
2c09574f18
@ -10337,6 +10337,10 @@ namespace ts {
|
||||
if (!type) {
|
||||
return undefined;
|
||||
}
|
||||
// If the contextual signature has fewer parameters than the function expression, do not use it
|
||||
if (isFunctionExpressionOrArrowFunction(node) && isAritySmaller(type, node)) {
|
||||
return undefined;
|
||||
}
|
||||
if (!(type.flags & TypeFlags.Union)) {
|
||||
return getNonGenericSignature(type);
|
||||
}
|
||||
@ -10371,6 +10375,26 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function isAritySmaller(sourceType: Type, target: FunctionExpression | ArrowFunction) {
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
if (target.parameters.length && parameterIsThisKeyword(target.parameters[0])) {
|
||||
targetParameterCount--;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the mapper implies an inference context. Specifically, there are 4 possible values
|
||||
* for a mapper. Let's go through each one of them:
|
||||
@ -11884,12 +11908,6 @@ 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 to avoid fixing incorrect
|
||||
// contextual types to the function expression parameters.
|
||||
if (!reportErrors && isAritySmaller(paramType, arg)) {
|
||||
return false;
|
||||
}
|
||||
argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
|
||||
}
|
||||
|
||||
@ -11904,16 +11922,6 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function isAritySmaller(sourceType: Type, target: Expression) {
|
||||
if (isFunctionExpressionOrArrowFunction(target) && isFunctionType(sourceType)) {
|
||||
const sourceSignatures = getSignaturesOfType(sourceType, SignatureKind.Call);
|
||||
const sourceLengths = sourceSignatures.map(sig => !sig.hasRestParameter ? sig.parameters.length : Number.MAX_VALUE);
|
||||
return forEach(sourceLengths, len => len < target.parameters.length);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise.
|
||||
*/
|
||||
|
||||
@ -7,9 +7,9 @@ var use: Overload;
|
||||
use((req, res) => {});
|
||||
>use((req, res) => {}) : void
|
||||
>use : Overload
|
||||
>(req, res) => {} : (req: number, res: number) => void
|
||||
>req : number
|
||||
>res : number
|
||||
>(req, res) => {} : (req: any, res: any) => void
|
||||
>req : any
|
||||
>res : any
|
||||
|
||||
interface Overload {
|
||||
>Overload : Overload
|
||||
|
||||
@ -122,8 +122,8 @@ module GenericParameter {
|
||||
>'' : ""
|
||||
|
||||
var r11 = foo6(<T>(x: T, y?: T) => ''); // any => string (+1 overload)
|
||||
>r11 : any
|
||||
>foo6(<T>(x: T, y?: T) => '') : any
|
||||
>r11 : { (x: any): string; (x: any, y?: any): string; }
|
||||
>foo6(<T>(x: T, y?: T) => '') : { (x: any): string; (x: any, y?: any): string; }
|
||||
>foo6 : <T>(cb: { (x: T): string; (x: T, y?: T): string; }) => { (x: T): string; (x: T, y?: T): string; }
|
||||
><T>(x: T, y?: T) => '' : <T>(x: T, y?: T) => string
|
||||
>T : T
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(12,11): error TS2345: Argument of type '(t1: D, t2: C, t3: any) => void' is not assignable to parameter of type '(t: C, t1: C) => void'.
|
||||
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(13,11): error TS2345: Argument of type '(t1: C, t2: D, t3: any) => void' is not assignable to parameter of type '(t: C, t1: C) => void'.
|
||||
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(14,11): error TS2345: Argument of type '(t1: C, t2: C, t3: D) => void' is not assignable to parameter of type '(t: C, t1: C) => void'.
|
||||
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(12,11): error TS2345: Argument of type '(t1: D, t2: any, t3: any) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
|
||||
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(13,11): error TS2345: Argument of type '(t1: any, t2: D, t3: any) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
|
||||
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(14,11): error TS2345: Argument of type '(t1: any, t2: any, t3: D) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts (3 errors) ====
|
||||
@ -17,11 +17,11 @@ tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partial
|
||||
// more args
|
||||
testError((t1: D, t2, t3) => {})
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '(t1: D, t2: C, t3: any) => void' is not assignable to parameter of type '(t: C, t1: C) => void'.
|
||||
!!! error TS2345: Argument of type '(t1: D, t2: any, t3: any) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
|
||||
testError((t1, t2: D, t3) => {})
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '(t1: C, t2: D, t3: any) => void' is not assignable to parameter of type '(t: C, t1: C) => void'.
|
||||
!!! error TS2345: Argument of type '(t1: any, t2: D, t3: any) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
|
||||
testError((t1, t2, t3: D) => {})
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '(t1: C, t2: C, t3: D) => void' is not assignable to parameter of type '(t: C, t1: C) => void'.
|
||||
!!! error TS2345: Argument of type '(t1: any, t2: any, t3: D) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user