diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 683874e2d10f0..bdda8d18770e6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -39498,7 +39498,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTypeOfSymbol(getSymbolOfDeclaration(node)); } - function contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode) { + function contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode = CheckMode.Normal) { const links = getNodeLinks(node); // Check if function expression is contextually typed and assign parameter types if so. if (!(links.flags & NodeCheckFlags.ContextChecked)) { @@ -39516,7 +39516,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (contextualSignature) { const inferenceContext = getInferenceContext(node); let instantiatedContextualSignature: Signature | undefined; - if (checkMode && checkMode & CheckMode.Inferential) { + if (checkMode & CheckMode.Inferential) { inferFromAnnotatedParametersAndReturn(signature, contextualSignature, inferenceContext!); const restType = getEffectiveRestType(contextualSignature); if (restType && restType.flags & TypeFlags.TypeParameter) { @@ -39534,12 +39534,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (contextualSignature && !node.typeParameters && contextualSignature.parameters.length > node.parameters.length) { const inferenceContext = getInferenceContext(node); - if (checkMode && checkMode & CheckMode.Inferential) { + if (checkMode & CheckMode.Inferential) { inferFromAnnotatedParametersAndReturn(signature, contextualSignature, inferenceContext!); } } if (contextualSignature && !getReturnTypeFromAnnotation(node) && !signature.resolvedReturnType) { - const returnType = getReturnTypeFromBody(node, checkMode); + // `.resolvedReturnType` is cached indefinitely so the return type here has to be computed without `CheckMode.SkipContextSensitive` + // otherwise `anyFunctionType` could leak as part of the computed (and cached) return type + const returnType = getReturnTypeFromBody(node, checkMode & ~CheckMode.SkipContextSensitive); if (!signature.resolvedReturnType) { signature.resolvedReturnType = returnType; } diff --git a/tests/baselines/reference/contextualTypingGenericFunction2.errors.txt b/tests/baselines/reference/contextualTypingGenericFunction2.errors.txt new file mode 100644 index 0000000000000..6c13121fb4ae0 --- /dev/null +++ b/tests/baselines/reference/contextualTypingGenericFunction2.errors.txt @@ -0,0 +1,115 @@ +contextualTypingGenericFunction2.ts(10,3): error TS2322: Type '(params: T) => (a: boolean, b: unknown) => 1 | 0' is not assignable to type '(params: T) => (context: number, params: T) => number'. + Type '(a: boolean, b: unknown) => 1 | 0' is not assignable to type '(context: number, params: T) => number'. + Types of parameters 'a' and 'context' are incompatible. + Type 'number' is not assignable to type 'boolean'. +contextualTypingGenericFunction2.ts(18,3): error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: T) => (context: number, params: T) => number'. + Call signature return types '(a: number, b: unknown) => boolean' and '(context: number, params: T) => number' are incompatible. + Type 'boolean' is not assignable to type 'number'. +contextualTypingGenericFunction2.ts(26,3): error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: T) => (context: number, params: T) => number'. + Call signature return types '(a: number, b: unknown) => boolean' and '(context: number, params: T) => number' are incompatible. + Type 'boolean' is not assignable to type 'number'. +contextualTypingGenericFunction2.ts(39,3): error TS2322: Type '(params: T) => (a: boolean, b: unknown) => 1 | 0' is not assignable to type '(params: unknown) => (context: number, params: unknown) => number'. + Type '(a: boolean, b: unknown) => 1 | 0' is not assignable to type '(context: number, params: unknown) => number'. + Types of parameters 'a' and 'context' are incompatible. + Type 'number' is not assignable to type 'boolean'. +contextualTypingGenericFunction2.ts(47,3): error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: T) => (context: number, params: T) => number'. + Call signature return types '(a: number, b: unknown) => boolean' and '(context: number, params: T) => number' are incompatible. + Type 'boolean' is not assignable to type 'number'. +contextualTypingGenericFunction2.ts(55,3): error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: T) => (context: number, params: T) => number'. + Call signature return types '(a: number, b: unknown) => boolean' and '(context: number, params: T) => number' are incompatible. + Type 'boolean' is not assignable to type 'number'. + + +==== contextualTypingGenericFunction2.ts (6 errors) ==== + // https://github.com/microsoft/TypeScript/issues/61979 + + declare function fn

(config: { + callback: (params: P) => (context: number, params: P) => number; + unrelated?: (arg: string) => void; + }): (params: P) => number; + + // should error + export const result1 = fn({ + callback: (params: T) => { + ~~~~~~~~ +!!! error TS2322: Type '(params: T) => (a: boolean, b: unknown) => 1 | 0' is not assignable to type '(params: T) => (context: number, params: T) => number'. +!!! error TS2322: Type '(a: boolean, b: unknown) => 1 | 0' is not assignable to type '(context: number, params: T) => number'. +!!! error TS2322: Types of parameters 'a' and 'context' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'boolean'. +!!! related TS6500 contextualTypingGenericFunction2.ts:4:3: The expected type comes from property 'callback' which is declared here on type '{ callback: (params: T) => (context: number, params: T) => number; unrelated?: ((arg: string) => void) | undefined; }' + return (a: boolean, b) => (a ? 1 : 0); + }, + unrelated: (_) => {}, + }); + + // should error + export const result2 = fn({ + callback: (params: T) => { + ~~~~~~~~ +!!! error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: T) => (context: number, params: T) => number'. +!!! error TS2322: Call signature return types '(a: number, b: unknown) => boolean' and '(context: number, params: T) => number' are incompatible. +!!! error TS2322: Type 'boolean' is not assignable to type 'number'. +!!! related TS6500 contextualTypingGenericFunction2.ts:4:3: The expected type comes from property 'callback' which is declared here on type '{ callback: (params: T) => (context: number, params: T) => number; unrelated?: ((arg: string) => void) | undefined; }' + return (a, b): boolean => true; + }, + unrelated: (_) => {}, + }); + + // should error + export const result3 = fn({ + callback: (params: T) => { + ~~~~~~~~ +!!! error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: T) => (context: number, params: T) => number'. +!!! error TS2322: Call signature return types '(a: number, b: unknown) => boolean' and '(context: number, params: T) => number' are incompatible. +!!! error TS2322: Type 'boolean' is not assignable to type 'number'. +!!! related TS6500 contextualTypingGenericFunction2.ts:4:3: The expected type comes from property 'callback' which is declared here on type '{ callback: (params: T) => (context: number, params: T) => number; unrelated?: ((arg: string) => void) | undefined; }' + return (a, b) => true; + }, + unrelated: (_) => {}, + }); + + declare function fn2

(config: { + callback: (params: P) => (context: number, params: P) => number; + unrelated?: (arg: string) => void; + }): any; + + // should error + export const result4 = fn2({ + callback: (params: T) => { + ~~~~~~~~ +!!! error TS2322: Type '(params: T) => (a: boolean, b: unknown) => 1 | 0' is not assignable to type '(params: unknown) => (context: number, params: unknown) => number'. +!!! error TS2322: Type '(a: boolean, b: unknown) => 1 | 0' is not assignable to type '(context: number, params: unknown) => number'. +!!! error TS2322: Types of parameters 'a' and 'context' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'boolean'. +!!! related TS6500 contextualTypingGenericFunction2.ts:33:3: The expected type comes from property 'callback' which is declared here on type '{ callback: (params: unknown) => (context: number, params: unknown) => number; unrelated?: ((arg: string) => void) | undefined; }' + return (a: boolean, b) => (a ? 1 : 0); + }, + unrelated: (_) => {}, + }); + + // should error + export const result5 = fn({ + callback: (params: T) => { + ~~~~~~~~ +!!! error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: T) => (context: number, params: T) => number'. +!!! error TS2322: Call signature return types '(a: number, b: unknown) => boolean' and '(context: number, params: T) => number' are incompatible. +!!! error TS2322: Type 'boolean' is not assignable to type 'number'. +!!! related TS6500 contextualTypingGenericFunction2.ts:4:3: The expected type comes from property 'callback' which is declared here on type '{ callback: (params: T) => (context: number, params: T) => number; unrelated?: ((arg: string) => void) | undefined; }' + return (a, b): boolean => true; + }, + unrelated: (_) => {}, + }); + + // should error + export const result6 = fn({ + callback: (params: T) => { + ~~~~~~~~ +!!! error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: T) => (context: number, params: T) => number'. +!!! error TS2322: Call signature return types '(a: number, b: unknown) => boolean' and '(context: number, params: T) => number' are incompatible. +!!! error TS2322: Type 'boolean' is not assignable to type 'number'. +!!! related TS6500 contextualTypingGenericFunction2.ts:4:3: The expected type comes from property 'callback' which is declared here on type '{ callback: (params: T) => (context: number, params: T) => number; unrelated?: ((arg: string) => void) | undefined; }' + return (a, b) => true; + }, + unrelated: (_) => {}, + }); + \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypingGenericFunction2.symbols b/tests/baselines/reference/contextualTypingGenericFunction2.symbols new file mode 100644 index 0000000000000..674d0b621d480 --- /dev/null +++ b/tests/baselines/reference/contextualTypingGenericFunction2.symbols @@ -0,0 +1,179 @@ +//// [tests/cases/compiler/contextualTypingGenericFunction2.ts] //// + +=== contextualTypingGenericFunction2.ts === +// https://github.com/microsoft/TypeScript/issues/61979 + +declare function fn

(config: { +>fn : Symbol(fn, Decl(contextualTypingGenericFunction2.ts, 0, 0)) +>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 2, 20)) +>config : Symbol(config, Decl(contextualTypingGenericFunction2.ts, 2, 23)) + + callback: (params: P) => (context: number, params: P) => number; +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 2, 32)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 3, 13)) +>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 2, 20)) +>context : Symbol(context, Decl(contextualTypingGenericFunction2.ts, 3, 28)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 3, 44)) +>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 2, 20)) + + unrelated?: (arg: string) => void; +>unrelated : Symbol(unrelated, Decl(contextualTypingGenericFunction2.ts, 3, 66)) +>arg : Symbol(arg, Decl(contextualTypingGenericFunction2.ts, 4, 15)) + +}): (params: P) => number; +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 5, 5)) +>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 2, 20)) + +// should error +export const result1 = fn({ +>result1 : Symbol(result1, Decl(contextualTypingGenericFunction2.ts, 8, 12)) +>fn : Symbol(fn, Decl(contextualTypingGenericFunction2.ts, 0, 0)) + + callback: (params: T) => { +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 8, 27)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 9, 13)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 9, 17)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 9, 13)) + + return (a: boolean, b) => (a ? 1 : 0); +>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 10, 12)) +>b : Symbol(b, Decl(contextualTypingGenericFunction2.ts, 10, 23)) +>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 10, 12)) + + }, + unrelated: (_) => {}, +>unrelated : Symbol(unrelated, Decl(contextualTypingGenericFunction2.ts, 11, 4)) +>_ : Symbol(_, Decl(contextualTypingGenericFunction2.ts, 12, 14)) + +}); + +// should error +export const result2 = fn({ +>result2 : Symbol(result2, Decl(contextualTypingGenericFunction2.ts, 16, 12)) +>fn : Symbol(fn, Decl(contextualTypingGenericFunction2.ts, 0, 0)) + + callback: (params: T) => { +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 16, 27)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 17, 13)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 17, 17)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 17, 13)) + + return (a, b): boolean => true; +>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 18, 12)) +>b : Symbol(b, Decl(contextualTypingGenericFunction2.ts, 18, 14)) + + }, + unrelated: (_) => {}, +>unrelated : Symbol(unrelated, Decl(contextualTypingGenericFunction2.ts, 19, 4)) +>_ : Symbol(_, Decl(contextualTypingGenericFunction2.ts, 20, 14)) + +}); + +// should error +export const result3 = fn({ +>result3 : Symbol(result3, Decl(contextualTypingGenericFunction2.ts, 24, 12)) +>fn : Symbol(fn, Decl(contextualTypingGenericFunction2.ts, 0, 0)) + + callback: (params: T) => { +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 24, 27)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 25, 13)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 25, 17)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 25, 13)) + + return (a, b) => true; +>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 26, 12)) +>b : Symbol(b, Decl(contextualTypingGenericFunction2.ts, 26, 14)) + + }, + unrelated: (_) => {}, +>unrelated : Symbol(unrelated, Decl(contextualTypingGenericFunction2.ts, 27, 4)) +>_ : Symbol(_, Decl(contextualTypingGenericFunction2.ts, 28, 14)) + +}); + +declare function fn2

(config: { +>fn2 : Symbol(fn2, Decl(contextualTypingGenericFunction2.ts, 29, 3)) +>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 31, 21)) +>config : Symbol(config, Decl(contextualTypingGenericFunction2.ts, 31, 24)) + + callback: (params: P) => (context: number, params: P) => number; +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 31, 33)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 32, 13)) +>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 31, 21)) +>context : Symbol(context, Decl(contextualTypingGenericFunction2.ts, 32, 28)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 32, 44)) +>P : Symbol(P, Decl(contextualTypingGenericFunction2.ts, 31, 21)) + + unrelated?: (arg: string) => void; +>unrelated : Symbol(unrelated, Decl(contextualTypingGenericFunction2.ts, 32, 66)) +>arg : Symbol(arg, Decl(contextualTypingGenericFunction2.ts, 33, 15)) + +}): any; + +// should error +export const result4 = fn2({ +>result4 : Symbol(result4, Decl(contextualTypingGenericFunction2.ts, 37, 12)) +>fn2 : Symbol(fn2, Decl(contextualTypingGenericFunction2.ts, 29, 3)) + + callback: (params: T) => { +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 37, 28)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 38, 13)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 38, 17)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 38, 13)) + + return (a: boolean, b) => (a ? 1 : 0); +>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 39, 12)) +>b : Symbol(b, Decl(contextualTypingGenericFunction2.ts, 39, 23)) +>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 39, 12)) + + }, + unrelated: (_) => {}, +>unrelated : Symbol(unrelated, Decl(contextualTypingGenericFunction2.ts, 40, 4)) +>_ : Symbol(_, Decl(contextualTypingGenericFunction2.ts, 41, 14)) + +}); + +// should error +export const result5 = fn({ +>result5 : Symbol(result5, Decl(contextualTypingGenericFunction2.ts, 45, 12)) +>fn : Symbol(fn, Decl(contextualTypingGenericFunction2.ts, 0, 0)) + + callback: (params: T) => { +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 45, 27)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 46, 13)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 46, 17)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 46, 13)) + + return (a, b): boolean => true; +>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 47, 12)) +>b : Symbol(b, Decl(contextualTypingGenericFunction2.ts, 47, 14)) + + }, + unrelated: (_) => {}, +>unrelated : Symbol(unrelated, Decl(contextualTypingGenericFunction2.ts, 48, 4)) +>_ : Symbol(_, Decl(contextualTypingGenericFunction2.ts, 49, 14)) + +}); + +// should error +export const result6 = fn({ +>result6 : Symbol(result6, Decl(contextualTypingGenericFunction2.ts, 53, 12)) +>fn : Symbol(fn, Decl(contextualTypingGenericFunction2.ts, 0, 0)) + + callback: (params: T) => { +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 53, 27)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 54, 13)) +>params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 54, 17)) +>T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 54, 13)) + + return (a, b) => true; +>a : Symbol(a, Decl(contextualTypingGenericFunction2.ts, 55, 12)) +>b : Symbol(b, Decl(contextualTypingGenericFunction2.ts, 55, 14)) + + }, + unrelated: (_) => {}, +>unrelated : Symbol(unrelated, Decl(contextualTypingGenericFunction2.ts, 56, 4)) +>_ : Symbol(_, Decl(contextualTypingGenericFunction2.ts, 57, 14)) + +}); + diff --git a/tests/baselines/reference/contextualTypingGenericFunction2.types b/tests/baselines/reference/contextualTypingGenericFunction2.types new file mode 100644 index 0000000000000..72332c93c5e6d --- /dev/null +++ b/tests/baselines/reference/contextualTypingGenericFunction2.types @@ -0,0 +1,311 @@ +//// [tests/cases/compiler/contextualTypingGenericFunction2.ts] //// + +=== contextualTypingGenericFunction2.ts === +// https://github.com/microsoft/TypeScript/issues/61979 + +declare function fn

(config: { +>fn :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => (params: P) => number +> : ^ ^^ ^^ ^^^^^ +>config : { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ + + callback: (params: P) => (context: number, params: P) => number; +>callback : (params: P) => (context: number, params: P) => number +> : ^ ^^ ^^^^^ +>params : P +> : ^ +>context : number +> : ^^^^^^ +>params : P +> : ^ + + unrelated?: (arg: string) => void; +>unrelated : ((arg: string) => void) | undefined +> : ^^ ^^ ^^^^^ ^^^^^^^^^^^^^ +>arg : string +> : ^^^^^^ + +}): (params: P) => number; +>params : P +> : ^ + +// should error +export const result1 = fn({ +>result1 : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn({ callback: (params: T) => { return (a: boolean, b) => (a ? 1 : 0); }, unrelated: (_) => {},}) : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => (params: P) => number +> : ^ ^^ ^^ ^^^^^ +>{ callback: (params: T) => { return (a: boolean, b) => (a ? 1 : 0); }, unrelated: (_) => {},} : { callback: (params: T) => (a: boolean, b: unknown) => 1 | 0; unrelated: (_: string) => void; } +> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ + + callback: (params: T) => { +>callback : (params: T) => (a: boolean, b: unknown) => 1 | 0 +> : ^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>(params: T) => { return (a: boolean, b) => (a ? 1 : 0); } : (params: T) => (a: boolean, b: unknown) => 1 | 0 +> : ^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>params : T +> : ^ + + return (a: boolean, b) => (a ? 1 : 0); +>(a: boolean, b) => (a ? 1 : 0) : (a: boolean, b: unknown) => 1 | 0 +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>a : boolean +> : ^^^^^^^ +>b : unknown +> : ^^^^^^^ +>(a ? 1 : 0) : 0 | 1 +> : ^^^^^ +>a ? 1 : 0 : 0 | 1 +> : ^^^^^ +>a : boolean +> : ^^^^^^^ +>1 : 1 +> : ^ +>0 : 0 +> : ^ + + }, + unrelated: (_) => {}, +>unrelated : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>(_) => {} : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>_ : string +> : ^^^^^^ + +}); + +// should error +export const result2 = fn({ +>result2 : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn({ callback: (params: T) => { return (a, b): boolean => true; }, unrelated: (_) => {},}) : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => (params: P) => number +> : ^ ^^ ^^ ^^^^^ +>{ callback: (params: T) => { return (a, b): boolean => true; }, unrelated: (_) => {},} : { callback: (params: T) => (a: number, b: unknown) => boolean; unrelated: (_: string) => void; } +> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ + + callback: (params: T) => { +>callback : (params: T) => (a: number, b: unknown) => boolean +> : ^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ +>(params: T) => { return (a, b): boolean => true; } : (params: T) => (a: number, b: unknown) => boolean +> : ^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ +>params : T +> : ^ + + return (a, b): boolean => true; +>(a, b): boolean => true : (a: number, b: unknown) => boolean +> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : unknown +> : ^^^^^^^ +>true : true +> : ^^^^ + + }, + unrelated: (_) => {}, +>unrelated : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>(_) => {} : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>_ : string +> : ^^^^^^ + +}); + +// should error +export const result3 = fn({ +>result3 : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn({ callback: (params: T) => { return (a, b) => true; }, unrelated: (_) => {},}) : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => (params: P) => number +> : ^ ^^ ^^ ^^^^^ +>{ callback: (params: T) => { return (a, b) => true; }, unrelated: (_) => {},} : { callback: (params: T) => (a: number, b: unknown) => boolean; unrelated: (_: string) => void; } +> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ + + callback: (params: T) => { +>callback : (params: T) => (a: number, b: unknown) => boolean +> : ^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ +>(params: T) => { return (a, b) => true; } : (params: T) => (a: number, b: unknown) => boolean +> : ^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ +>params : T +> : ^ + + return (a, b) => true; +>(a, b) => true : (a: number, b: unknown) => boolean +> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : unknown +> : ^^^^^^^ +>true : true +> : ^^^^ + + }, + unrelated: (_) => {}, +>unrelated : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>(_) => {} : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>_ : string +> : ^^^^^^ + +}); + +declare function fn2

(config: { +>fn2 :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => any +> : ^ ^^ ^^ ^^^^^ +>config : { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ + + callback: (params: P) => (context: number, params: P) => number; +>callback : (params: P) => (context: number, params: P) => number +> : ^ ^^ ^^^^^ +>params : P +> : ^ +>context : number +> : ^^^^^^ +>params : P +> : ^ + + unrelated?: (arg: string) => void; +>unrelated : ((arg: string) => void) | undefined +> : ^^ ^^ ^^^^^ ^^^^^^^^^^^^^ +>arg : string +> : ^^^^^^ + +}): any; + +// should error +export const result4 = fn2({ +>result4 : any +> : ^^^ +>fn2({ callback: (params: T) => { return (a: boolean, b) => (a ? 1 : 0); }, unrelated: (_) => {},}) : any +> : ^^^ +>fn2 :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => any +> : ^ ^^ ^^ ^^^^^ +>{ callback: (params: T) => { return (a: boolean, b) => (a ? 1 : 0); }, unrelated: (_) => {},} : { callback: (params: T) => (a: boolean, b: unknown) => 1 | 0; unrelated: (_: string) => void; } +> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ + + callback: (params: T) => { +>callback : (params: T) => (a: boolean, b: unknown) => 1 | 0 +> : ^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>(params: T) => { return (a: boolean, b) => (a ? 1 : 0); } : (params: T) => (a: boolean, b: unknown) => 1 | 0 +> : ^ ^^ ^^ ^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>params : T +> : ^ + + return (a: boolean, b) => (a ? 1 : 0); +>(a: boolean, b) => (a ? 1 : 0) : (a: boolean, b: unknown) => 1 | 0 +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>a : boolean +> : ^^^^^^^ +>b : unknown +> : ^^^^^^^ +>(a ? 1 : 0) : 0 | 1 +> : ^^^^^ +>a ? 1 : 0 : 0 | 1 +> : ^^^^^ +>a : boolean +> : ^^^^^^^ +>1 : 1 +> : ^ +>0 : 0 +> : ^ + + }, + unrelated: (_) => {}, +>unrelated : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>(_) => {} : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>_ : string +> : ^^^^^^ + +}); + +// should error +export const result5 = fn({ +>result5 : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn({ callback: (params: T) => { return (a, b): boolean => true; }, unrelated: (_) => {},}) : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => (params: P) => number +> : ^ ^^ ^^ ^^^^^ +>{ callback: (params: T) => { return (a, b): boolean => true; }, unrelated: (_) => {},} : { callback: (params: T) => (a: number, b: unknown) => boolean; unrelated: (_: string) => void; } +> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ + + callback: (params: T) => { +>callback : (params: T) => (a: number, b: unknown) => boolean +> : ^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ +>(params: T) => { return (a, b): boolean => true; } : (params: T) => (a: number, b: unknown) => boolean +> : ^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ +>params : T +> : ^ + + return (a, b): boolean => true; +>(a, b): boolean => true : (a: number, b: unknown) => boolean +> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : unknown +> : ^^^^^^^ +>true : true +> : ^^^^ + + }, + unrelated: (_) => {}, +>unrelated : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>(_) => {} : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>_ : string +> : ^^^^^^ + +}); + +// should error +export const result6 = fn({ +>result6 : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn({ callback: (params: T) => { return (a, b) => true; }, unrelated: (_) => {},}) : (params: unknown) => number +> : ^ ^^^^^^^^^^^^^^ +>fn :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => (params: P) => number +> : ^ ^^ ^^ ^^^^^ +>{ callback: (params: T) => { return (a, b) => true; }, unrelated: (_) => {},} : { callback: (params: T) => (a: number, b: unknown) => boolean; unrelated: (_: string) => void; } +> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ + + callback: (params: T) => { +>callback : (params: T) => (a: number, b: unknown) => boolean +> : ^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ +>(params: T) => { return (a, b) => true; } : (params: T) => (a: number, b: unknown) => boolean +> : ^ ^^ ^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ +>params : T +> : ^ + + return (a, b) => true; +>(a, b) => true : (a: number, b: unknown) => boolean +> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : unknown +> : ^^^^^^^ +>true : true +> : ^^^^ + + }, + unrelated: (_) => {}, +>unrelated : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>(_) => {} : (_: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>_ : string +> : ^^^^^^ + +}); + diff --git a/tests/cases/compiler/contextualTypingGenericFunction2.ts b/tests/cases/compiler/contextualTypingGenericFunction2.ts new file mode 100644 index 0000000000000..ba73e192e52f8 --- /dev/null +++ b/tests/cases/compiler/contextualTypingGenericFunction2.ts @@ -0,0 +1,62 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/61979 + +declare function fn

(config: { + callback: (params: P) => (context: number, params: P) => number; + unrelated?: (arg: string) => void; +}): (params: P) => number; + +// should error +export const result1 = fn({ + callback: (params: T) => { + return (a: boolean, b) => (a ? 1 : 0); + }, + unrelated: (_) => {}, +}); + +// should error +export const result2 = fn({ + callback: (params: T) => { + return (a, b): boolean => true; + }, + unrelated: (_) => {}, +}); + +// should error +export const result3 = fn({ + callback: (params: T) => { + return (a, b) => true; + }, + unrelated: (_) => {}, +}); + +declare function fn2

(config: { + callback: (params: P) => (context: number, params: P) => number; + unrelated?: (arg: string) => void; +}): any; + +// should error +export const result4 = fn2({ + callback: (params: T) => { + return (a: boolean, b) => (a ? 1 : 0); + }, + unrelated: (_) => {}, +}); + +// should error +export const result5 = fn({ + callback: (params: T) => { + return (a, b): boolean => true; + }, + unrelated: (_) => {}, +}); + +// should error +export const result6 = fn({ + callback: (params: T) => { + return (a, b) => true; + }, + unrelated: (_) => {}, +});