From d3f3b5bef08facc74caa2bb00ebf92968c4211cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 2 Sep 2026 11:47:42 +0200 Subject: [PATCH 1/2] Fixed `anyFunctionType` leak --- tsc/internal/checker/checker.go | 4 +- ...ontextualTypingGenericFunction2.errors.txt | 115 ++++++++++ .../contextualTypingGenericFunction2.symbols | 179 ++++++++++++++++ .../contextualTypingGenericFunction2.types | 202 ++++++++++++++++++ .../contextualTypingGenericFunction2.ts | 62 ++++++ 5 files changed, 561 insertions(+), 1 deletion(-) create mode 100644 tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.types create mode 100644 tsc/testdata/tests/cases/compiler/contextualTypingGenericFunction2.ts diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index fb3c33c01b814..50dfdf1f352b0 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -10285,7 +10285,9 @@ func (c *Checker) contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node } } if contextualSignature != nil && c.getReturnTypeFromAnnotation(node) == nil && signature.resolvedReturnType == nil { - returnType := c.getReturnTypeFromBody(node, checkMode) + // resolvedReturnType is cached indefinitely, so the return type here has to be computed without CheckModeSkipContextSensitive; + // otherwise anyFunctionType could leak as part of the computed (and cached) return type. + returnType := c.getReturnTypeFromBody(node, checkMode&^CheckModeSkipContextSensitive) if signature.resolvedReturnType == nil { signature.resolvedReturnType = returnType } diff --git a/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.errors.txt b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.errors.txt new file mode 100644 index 0000000000000..44c9b33ac5dd7 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.errors.txt @@ -0,0 +1,115 @@ +contextualTypingGenericFunction2.ts(10,3): error TS2322: Type '(params: T) => (a: boolean, b: unknown) => 0 | 1' is not assignable to type '(params: T) => (context: number, params: T) => number'. + Type '(a: boolean, b: unknown) => 0 | 1' 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'. + Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. + 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'. + Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. + Type 'boolean' is not assignable to type 'number'. +contextualTypingGenericFunction2.ts(39,3): error TS2322: Type '(params: T) => (a: boolean, b: unknown) => 0 | 1' is not assignable to type '(params: unknown) => (context: number, params: unknown) => number'. + Type '(a: boolean, b: unknown) => 0 | 1' 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'. + Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. + 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'. + Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. + 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) => 0 | 1' is not assignable to type '(params: T) => (context: number, params: T) => number'. +!!! error TS2322: Type '(a: boolean, b: unknown) => 0 | 1' 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: Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. +!!! 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: Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. +!!! 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) => 0 | 1' is not assignable to type '(params: unknown) => (context: number, params: unknown) => number'. +!!! error TS2322: Type '(a: boolean, b: unknown) => 0 | 1' 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: Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. +!!! 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: Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. +!!! 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/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.symbols b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.symbols new file mode 100644 index 0000000000000..674d0b621d480 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/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/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.types b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.types new file mode 100644 index 0000000000000..c5200a68c88d0 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.types @@ -0,0 +1,202 @@ +//// [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) => 0 | 1; unrelated: (_: string) => void; } + + callback: (params: T) => { +>callback : (params: T) => (a: boolean, b: unknown) => 0 | 1 +>(params: T) => { return (a: boolean, b) => (a ? 1 : 0); } : (params: T) => (a: boolean, b: unknown) => 0 | 1 +>params : T + + return (a: boolean, b) => (a ? 1 : 0); +>(a: boolean, b) => (a ? 1 : 0) : (a: boolean, b: unknown) => 0 | 1 +>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) => 0 | 1; unrelated: (_: string) => void; } + + callback: (params: T) => { +>callback : (params: T) => (a: boolean, b: unknown) => 0 | 1 +>(params: T) => { return (a: boolean, b) => (a ? 1 : 0); } : (params: T) => (a: boolean, b: unknown) => 0 | 1 +>params : T + + return (a: boolean, b) => (a ? 1 : 0); +>(a: boolean, b) => (a ? 1 : 0) : (a: boolean, b: unknown) => 0 | 1 +>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/tsc/testdata/tests/cases/compiler/contextualTypingGenericFunction2.ts b/tsc/testdata/tests/cases/compiler/contextualTypingGenericFunction2.ts new file mode 100644 index 0000000000000..ba73e192e52f8 --- /dev/null +++ b/tsc/testdata/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: (_) => {}, +}); From 7f4cfef4f29939f4e17337c652abf354a963494e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 2 Sep 2026 13:25:38 +0200 Subject: [PATCH 2/2] Correct contextual typing test coverage --- ...ontextualTypingGenericFunction2.errors.txt | 24 +++++++++---------- .../contextualTypingGenericFunction2.symbols | 12 +++++----- .../contextualTypingGenericFunction2.types | 16 ++++++------- .../contextualTypingGenericFunction2.ts | 4 ++-- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.errors.txt b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.errors.txt index 44c9b33ac5dd7..d9617585b65f4 100644 --- a/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.errors.txt +++ b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.errors.txt @@ -12,11 +12,11 @@ contextualTypingGenericFunction2.ts(39,3): error TS2322: Type '(params: T) => Type '(a: boolean, b: unknown) => 0 | 1' 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'. - Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. +contextualTypingGenericFunction2.ts(47,3): error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: unknown) => (context: number, params: unknown) => number'. + Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: unknown) => number'. 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'. - Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. +contextualTypingGenericFunction2.ts(55,3): error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: unknown) => (context: number, params: unknown) => number'. + Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: unknown) => number'. Type 'boolean' is not assignable to type 'number'. @@ -88,26 +88,26 @@ contextualTypingGenericFunction2.ts(55,3): error TS2322: Type '(params: T) => }); // should error - export const result5 = fn({ + export const result5 = fn2({ 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: Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. +!!! error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: unknown) => (context: number, params: unknown) => number'. +!!! error TS2322: Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: unknown) => number'. !!! 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; }' +!!! 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, b): boolean => true; }, unrelated: (_) => {}, }); // should error - export const result6 = fn({ + export const result6 = fn2({ 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: Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: T) => number'. +!!! error TS2322: Type '(params: T) => (a: number, b: unknown) => boolean' is not assignable to type '(params: unknown) => (context: number, params: unknown) => number'. +!!! error TS2322: Type '(a: number, b: unknown) => boolean' is not assignable to type '(context: number, params: unknown) => number'. !!! 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; }' +!!! 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, b) => true; }, unrelated: (_) => {}, diff --git a/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.symbols b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.symbols index 674d0b621d480..e319edad2ba7f 100644 --- a/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.symbols +++ b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.symbols @@ -134,12 +134,12 @@ export const result4 = fn2({ }); // should error -export const result5 = fn({ +export const result5 = fn2({ >result5 : Symbol(result5, Decl(contextualTypingGenericFunction2.ts, 45, 12)) ->fn : Symbol(fn, Decl(contextualTypingGenericFunction2.ts, 0, 0)) +>fn2 : Symbol(fn2, Decl(contextualTypingGenericFunction2.ts, 29, 3)) callback: (params: T) => { ->callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 45, 27)) +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 45, 28)) >T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 46, 13)) >params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 46, 17)) >T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 46, 13)) @@ -156,12 +156,12 @@ export const result5 = fn({ }); // should error -export const result6 = fn({ +export const result6 = fn2({ >result6 : Symbol(result6, Decl(contextualTypingGenericFunction2.ts, 53, 12)) ->fn : Symbol(fn, Decl(contextualTypingGenericFunction2.ts, 0, 0)) +>fn2 : Symbol(fn2, Decl(contextualTypingGenericFunction2.ts, 29, 3)) callback: (params: T) => { ->callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 53, 27)) +>callback : Symbol(callback, Decl(contextualTypingGenericFunction2.ts, 53, 28)) >T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 54, 13)) >params : Symbol(params, Decl(contextualTypingGenericFunction2.ts, 54, 17)) >T : Symbol(T, Decl(contextualTypingGenericFunction2.ts, 54, 13)) diff --git a/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.types b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.types index c5200a68c88d0..1660f8bf544ad 100644 --- a/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.types +++ b/tsc/testdata/baselines/reference/compiler/contextualTypingGenericFunction2.types @@ -149,10 +149,10 @@ export const result4 = fn2({ }); // 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 +export const result5 = fn2({ +>result5 : any +>fn2({ callback: (params: T) => { return (a, b): boolean => true; }, unrelated: (_) => {},}) : any +>fn2 :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => any >{ callback: (params: T) => { return (a, b): boolean => true; }, unrelated: (_) => {},} : { callback: (params: T) => (a: number, b: unknown) => boolean; unrelated: (_: string) => void; } callback: (params: T) => { @@ -175,10 +175,10 @@ export const result5 = fn({ }); // 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 +export const result6 = fn2({ +>result6 : any +>fn2({ callback: (params: T) => { return (a, b) => true; }, unrelated: (_) => {},}) : any +>fn2 :

(config: { callback: (params: P) => (context: number, params: P) => number; unrelated?: (arg: string) => void; }) => any >{ callback: (params: T) => { return (a, b) => true; }, unrelated: (_) => {},} : { callback: (params: T) => (a: number, b: unknown) => boolean; unrelated: (_: string) => void; } callback: (params: T) => { diff --git a/tsc/testdata/tests/cases/compiler/contextualTypingGenericFunction2.ts b/tsc/testdata/tests/cases/compiler/contextualTypingGenericFunction2.ts index ba73e192e52f8..c57e81d414747 100644 --- a/tsc/testdata/tests/cases/compiler/contextualTypingGenericFunction2.ts +++ b/tsc/testdata/tests/cases/compiler/contextualTypingGenericFunction2.ts @@ -46,7 +46,7 @@ export const result4 = fn2({ }); // should error -export const result5 = fn({ +export const result5 = fn2({ callback: (params: T) => { return (a, b): boolean => true; }, @@ -54,7 +54,7 @@ export const result5 = fn({ }); // should error -export const result6 = fn({ +export const result6 = fn2({ callback: (params: T) => { return (a, b) => true; },