Skip to content

Commit a8944e6

Browse files
authored
Fix type parameter leak (#35949)
* Fix cloneSignature to include unionSignatures property * Add regression test
1 parent 024b8c1 commit a8944e6

File tree

5 files changed

+164
-0
lines changed

5 files changed

+164
-0
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8774,6 +8774,7 @@ namespace ts {
87748774
sig.minArgumentCount = minArgumentCount;
87758775
sig.target = undefined;
87768776
sig.mapper = undefined;
8777+
sig.unionSignatures = undefined;
87778778
return sig;
87788779
}
87798780

@@ -8782,6 +8783,7 @@ namespace ts {
87828783
/*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags);
87838784
result.target = sig.target;
87848785
result.mapper = sig.mapper;
8786+
result.unionSignatures = sig.unionSignatures;
87858787
return result;
87868788
}
87878789

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [typeParameterLeak.ts]
2+
// Repro from #35655
3+
4+
interface Box<T> { data: T }
5+
type BoxTypes = Box<{ x: string }> | Box<{ y: string }>;
6+
7+
type BoxFactoryFactory<TBox> = TBox extends Box<infer T> ? {
8+
(arg: T): BoxFactory<TBox> | undefined
9+
} : never;
10+
11+
interface BoxFactory<A> {
12+
getBox(): A,
13+
}
14+
15+
declare const f: BoxFactoryFactory<BoxTypes>;
16+
const b = f({ x: "", y: "" })?.getBox();
17+
if (b) {
18+
const x = b.data;
19+
}
20+
21+
22+
//// [typeParameterLeak.js]
23+
"use strict";
24+
// Repro from #35655
25+
var _a;
26+
var b = (_a = f({ x: "", y: "" })) === null || _a === void 0 ? void 0 : _a.getBox();
27+
if (b) {
28+
var x = b.data;
29+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
=== tests/cases/compiler/typeParameterLeak.ts ===
2+
// Repro from #35655
3+
4+
interface Box<T> { data: T }
5+
>Box : Symbol(Box, Decl(typeParameterLeak.ts, 0, 0))
6+
>T : Symbol(T, Decl(typeParameterLeak.ts, 2, 14))
7+
>data : Symbol(Box.data, Decl(typeParameterLeak.ts, 2, 18))
8+
>T : Symbol(T, Decl(typeParameterLeak.ts, 2, 14))
9+
10+
type BoxTypes = Box<{ x: string }> | Box<{ y: string }>;
11+
>BoxTypes : Symbol(BoxTypes, Decl(typeParameterLeak.ts, 2, 28))
12+
>Box : Symbol(Box, Decl(typeParameterLeak.ts, 0, 0))
13+
>x : Symbol(x, Decl(typeParameterLeak.ts, 3, 21))
14+
>Box : Symbol(Box, Decl(typeParameterLeak.ts, 0, 0))
15+
>y : Symbol(y, Decl(typeParameterLeak.ts, 3, 42))
16+
17+
type BoxFactoryFactory<TBox> = TBox extends Box<infer T> ? {
18+
>BoxFactoryFactory : Symbol(BoxFactoryFactory, Decl(typeParameterLeak.ts, 3, 56))
19+
>TBox : Symbol(TBox, Decl(typeParameterLeak.ts, 5, 23))
20+
>TBox : Symbol(TBox, Decl(typeParameterLeak.ts, 5, 23))
21+
>Box : Symbol(Box, Decl(typeParameterLeak.ts, 0, 0))
22+
>T : Symbol(T, Decl(typeParameterLeak.ts, 5, 53))
23+
24+
(arg: T): BoxFactory<TBox> | undefined
25+
>arg : Symbol(arg, Decl(typeParameterLeak.ts, 6, 3))
26+
>T : Symbol(T, Decl(typeParameterLeak.ts, 5, 53))
27+
>BoxFactory : Symbol(BoxFactory, Decl(typeParameterLeak.ts, 7, 10))
28+
>TBox : Symbol(TBox, Decl(typeParameterLeak.ts, 5, 23))
29+
30+
} : never;
31+
32+
interface BoxFactory<A> {
33+
>BoxFactory : Symbol(BoxFactory, Decl(typeParameterLeak.ts, 7, 10))
34+
>A : Symbol(A, Decl(typeParameterLeak.ts, 9, 21))
35+
36+
getBox(): A,
37+
>getBox : Symbol(BoxFactory.getBox, Decl(typeParameterLeak.ts, 9, 25))
38+
>A : Symbol(A, Decl(typeParameterLeak.ts, 9, 21))
39+
}
40+
41+
declare const f: BoxFactoryFactory<BoxTypes>;
42+
>f : Symbol(f, Decl(typeParameterLeak.ts, 13, 13))
43+
>BoxFactoryFactory : Symbol(BoxFactoryFactory, Decl(typeParameterLeak.ts, 3, 56))
44+
>BoxTypes : Symbol(BoxTypes, Decl(typeParameterLeak.ts, 2, 28))
45+
46+
const b = f({ x: "", y: "" })?.getBox();
47+
>b : Symbol(b, Decl(typeParameterLeak.ts, 14, 5))
48+
>f({ x: "", y: "" })?.getBox : Symbol(BoxFactory.getBox, Decl(typeParameterLeak.ts, 9, 25), Decl(typeParameterLeak.ts, 9, 25))
49+
>f : Symbol(f, Decl(typeParameterLeak.ts, 13, 13))
50+
>x : Symbol(x, Decl(typeParameterLeak.ts, 14, 13))
51+
>y : Symbol(y, Decl(typeParameterLeak.ts, 14, 20))
52+
>getBox : Symbol(BoxFactory.getBox, Decl(typeParameterLeak.ts, 9, 25), Decl(typeParameterLeak.ts, 9, 25))
53+
54+
if (b) {
55+
>b : Symbol(b, Decl(typeParameterLeak.ts, 14, 5))
56+
57+
const x = b.data;
58+
>x : Symbol(x, Decl(typeParameterLeak.ts, 16, 7))
59+
>b.data : Symbol(Box.data, Decl(typeParameterLeak.ts, 2, 18), Decl(typeParameterLeak.ts, 2, 18))
60+
>b : Symbol(b, Decl(typeParameterLeak.ts, 14, 5))
61+
>data : Symbol(Box.data, Decl(typeParameterLeak.ts, 2, 18), Decl(typeParameterLeak.ts, 2, 18))
62+
}
63+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
=== tests/cases/compiler/typeParameterLeak.ts ===
2+
// Repro from #35655
3+
4+
interface Box<T> { data: T }
5+
>data : T
6+
7+
type BoxTypes = Box<{ x: string }> | Box<{ y: string }>;
8+
>BoxTypes : BoxTypes
9+
>x : string
10+
>y : string
11+
12+
type BoxFactoryFactory<TBox> = TBox extends Box<infer T> ? {
13+
>BoxFactoryFactory : BoxFactoryFactory<TBox>
14+
15+
(arg: T): BoxFactory<TBox> | undefined
16+
>arg : T
17+
18+
} : never;
19+
20+
interface BoxFactory<A> {
21+
getBox(): A,
22+
>getBox : () => A
23+
}
24+
25+
declare const f: BoxFactoryFactory<BoxTypes>;
26+
>f : ((arg: { x: string; }) => BoxFactory<Box<{ x: string; }>> | undefined) | ((arg: { y: string; }) => BoxFactory<Box<{ y: string; }>> | undefined)
27+
28+
const b = f({ x: "", y: "" })?.getBox();
29+
>b : Box<{ x: string; }> | Box<{ y: string; }> | undefined
30+
>f({ x: "", y: "" })?.getBox() : Box<{ x: string; }> | Box<{ y: string; }> | undefined
31+
>f({ x: "", y: "" })?.getBox : (() => Box<{ x: string; }>) | (() => Box<{ y: string; }>) | undefined
32+
>f({ x: "", y: "" }) : BoxFactory<Box<{ x: string; }>> | BoxFactory<Box<{ y: string; }>> | undefined
33+
>f : ((arg: { x: string; }) => BoxFactory<Box<{ x: string; }>> | undefined) | ((arg: { y: string; }) => BoxFactory<Box<{ y: string; }>> | undefined)
34+
>{ x: "", y: "" } : { x: string; y: string; }
35+
>x : string
36+
>"" : ""
37+
>y : string
38+
>"" : ""
39+
>getBox : (() => Box<{ x: string; }>) | (() => Box<{ y: string; }>) | undefined
40+
41+
if (b) {
42+
>b : Box<{ x: string; }> | Box<{ y: string; }> | undefined
43+
44+
const x = b.data;
45+
>x : { x: string; } | { y: string; }
46+
>b.data : { x: string; } | { y: string; }
47+
>b : BoxTypes
48+
>data : { x: string; } | { y: string; }
49+
}
50+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @strict: true
2+
3+
// Repro from #35655
4+
5+
interface Box<T> { data: T }
6+
type BoxTypes = Box<{ x: string }> | Box<{ y: string }>;
7+
8+
type BoxFactoryFactory<TBox> = TBox extends Box<infer T> ? {
9+
(arg: T): BoxFactory<TBox> | undefined
10+
} : never;
11+
12+
interface BoxFactory<A> {
13+
getBox(): A,
14+
}
15+
16+
declare const f: BoxFactoryFactory<BoxTypes>;
17+
const b = f({ x: "", y: "" })?.getBox();
18+
if (b) {
19+
const x = b.data;
20+
}

0 commit comments

Comments
 (0)