Skip to content

Commit cd21478

Browse files
committed
Add tests
1 parent 4254fc2 commit cd21478

File tree

4 files changed

+325
-0
lines changed

4 files changed

+325
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
deeplyNestedMappedTypes.ts(9,7): error TS2322: Type 'Id<{ x: { y: { z: { a: { b: { c: number; }; }; }; }; }; }>' is not assignable to type 'Id<{ x: { y: { z: { a: { b: { c: string; }; }; }; }; }; }>'.
2+
The types of 'x.y.z.a.b.c' are incompatible between these types.
3+
Type 'number' is not assignable to type 'string'.
4+
5+
6+
==== deeplyNestedMappedTypes.ts (1 errors) ====
7+
// Simplified repro from #55535
8+
9+
type Id<T> = { [K in keyof T]: Id<T[K]> };
10+
11+
type Foo1 = Id<{ x: { y: { z: { a: { b: { c: number } } } } } }>;
12+
type Foo2 = Id<{ x: { y: { z: { a: { b: { c: string } } } } } }>;
13+
14+
declare const foo1: Foo1;
15+
const foo2: Foo2 = foo1; // Error expected
16+
~~~~
17+
!!! error TS2322: Type 'Id<{ x: { y: { z: { a: { b: { c: number; }; }; }; }; }; }>' is not assignable to type 'Id<{ x: { y: { z: { a: { b: { c: string; }; }; }; }; }; }>'.
18+
!!! error TS2322: The types of 'x.y.z.a.b.c' are incompatible between these types.
19+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
20+
21+
// Repro from issue linked in #55535
22+
23+
type RequiredDeep<T> = { [K in keyof T]-?: RequiredDeep<T[K]> };
24+
25+
type A = { a?: { b: { c: 1 | { d: 2000 } }}}
26+
type B = { a?: { b: { c: { d: { e: { f: { g: 2 }}}}, x: 1000 }}}
27+
28+
type C = RequiredDeep<A>;
29+
type D = RequiredDeep<B>;
30+
31+
type Test1 = [C, D] extends [D, C] ? true : false; // false
32+
type Test2 = C extends D ? true : false; // false
33+
type Test3 = D extends C ? true : false; // false
34+
35+
// Simplified repro from #54246
36+
37+
// Except for the final non-recursive Record<K, V>, object types produced by NestedRecord all have the same symbol
38+
// and thus are considered deeply nested after three levels of nesting. Ideally we'd detect that recursion in this
39+
// type always terminates, but we're unaware of a general algorithm that accomplishes this.
40+
41+
type NestedRecord<K extends string, V> = K extends `${infer K0}.${infer KR}` ? { [P in K0]: NestedRecord<KR, V> } : Record<K, V>;
42+
43+
type Bar1 = NestedRecord<"x.y.z.a.b.c", number>;
44+
type Bar2 = NestedRecord<"x.y.z.a.b.c", string>;
45+
46+
declare const bar1: Bar1;
47+
const bar2: Bar2 = bar1; // Error expected
48+
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//// [tests/cases/compiler/deeplyNestedMappedTypes.ts] ////
2+
3+
=== deeplyNestedMappedTypes.ts ===
4+
// Simplified repro from #55535
5+
6+
type Id<T> = { [K in keyof T]: Id<T[K]> };
7+
>Id : Symbol(Id, Decl(deeplyNestedMappedTypes.ts, 0, 0))
8+
>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 2, 8))
9+
>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 2, 16))
10+
>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 2, 8))
11+
>Id : Symbol(Id, Decl(deeplyNestedMappedTypes.ts, 0, 0))
12+
>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 2, 8))
13+
>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 2, 16))
14+
15+
type Foo1 = Id<{ x: { y: { z: { a: { b: { c: number } } } } } }>;
16+
>Foo1 : Symbol(Foo1, Decl(deeplyNestedMappedTypes.ts, 2, 42))
17+
>Id : Symbol(Id, Decl(deeplyNestedMappedTypes.ts, 0, 0))
18+
>x : Symbol(x, Decl(deeplyNestedMappedTypes.ts, 4, 16))
19+
>y : Symbol(y, Decl(deeplyNestedMappedTypes.ts, 4, 21))
20+
>z : Symbol(z, Decl(deeplyNestedMappedTypes.ts, 4, 26))
21+
>a : Symbol(a, Decl(deeplyNestedMappedTypes.ts, 4, 31))
22+
>b : Symbol(b, Decl(deeplyNestedMappedTypes.ts, 4, 36))
23+
>c : Symbol(c, Decl(deeplyNestedMappedTypes.ts, 4, 41))
24+
25+
type Foo2 = Id<{ x: { y: { z: { a: { b: { c: string } } } } } }>;
26+
>Foo2 : Symbol(Foo2, Decl(deeplyNestedMappedTypes.ts, 4, 65))
27+
>Id : Symbol(Id, Decl(deeplyNestedMappedTypes.ts, 0, 0))
28+
>x : Symbol(x, Decl(deeplyNestedMappedTypes.ts, 5, 16))
29+
>y : Symbol(y, Decl(deeplyNestedMappedTypes.ts, 5, 21))
30+
>z : Symbol(z, Decl(deeplyNestedMappedTypes.ts, 5, 26))
31+
>a : Symbol(a, Decl(deeplyNestedMappedTypes.ts, 5, 31))
32+
>b : Symbol(b, Decl(deeplyNestedMappedTypes.ts, 5, 36))
33+
>c : Symbol(c, Decl(deeplyNestedMappedTypes.ts, 5, 41))
34+
35+
declare const foo1: Foo1;
36+
>foo1 : Symbol(foo1, Decl(deeplyNestedMappedTypes.ts, 7, 13))
37+
>Foo1 : Symbol(Foo1, Decl(deeplyNestedMappedTypes.ts, 2, 42))
38+
39+
const foo2: Foo2 = foo1; // Error expected
40+
>foo2 : Symbol(foo2, Decl(deeplyNestedMappedTypes.ts, 8, 5))
41+
>Foo2 : Symbol(Foo2, Decl(deeplyNestedMappedTypes.ts, 4, 65))
42+
>foo1 : Symbol(foo1, Decl(deeplyNestedMappedTypes.ts, 7, 13))
43+
44+
// Repro from issue linked in #55535
45+
46+
type RequiredDeep<T> = { [K in keyof T]-?: RequiredDeep<T[K]> };
47+
>RequiredDeep : Symbol(RequiredDeep, Decl(deeplyNestedMappedTypes.ts, 8, 24))
48+
>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 12, 18))
49+
>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 12, 26))
50+
>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 12, 18))
51+
>RequiredDeep : Symbol(RequiredDeep, Decl(deeplyNestedMappedTypes.ts, 8, 24))
52+
>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 12, 18))
53+
>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 12, 26))
54+
55+
type A = { a?: { b: { c: 1 | { d: 2000 } }}}
56+
>A : Symbol(A, Decl(deeplyNestedMappedTypes.ts, 12, 64))
57+
>a : Symbol(a, Decl(deeplyNestedMappedTypes.ts, 14, 10))
58+
>b : Symbol(b, Decl(deeplyNestedMappedTypes.ts, 14, 16))
59+
>c : Symbol(c, Decl(deeplyNestedMappedTypes.ts, 14, 21))
60+
>d : Symbol(d, Decl(deeplyNestedMappedTypes.ts, 14, 30))
61+
62+
type B = { a?: { b: { c: { d: { e: { f: { g: 2 }}}}, x: 1000 }}}
63+
>B : Symbol(B, Decl(deeplyNestedMappedTypes.ts, 14, 44))
64+
>a : Symbol(a, Decl(deeplyNestedMappedTypes.ts, 15, 10))
65+
>b : Symbol(b, Decl(deeplyNestedMappedTypes.ts, 15, 16))
66+
>c : Symbol(c, Decl(deeplyNestedMappedTypes.ts, 15, 21))
67+
>d : Symbol(d, Decl(deeplyNestedMappedTypes.ts, 15, 26))
68+
>e : Symbol(e, Decl(deeplyNestedMappedTypes.ts, 15, 31))
69+
>f : Symbol(f, Decl(deeplyNestedMappedTypes.ts, 15, 36))
70+
>g : Symbol(g, Decl(deeplyNestedMappedTypes.ts, 15, 41))
71+
>x : Symbol(x, Decl(deeplyNestedMappedTypes.ts, 15, 52))
72+
73+
type C = RequiredDeep<A>;
74+
>C : Symbol(C, Decl(deeplyNestedMappedTypes.ts, 15, 64))
75+
>RequiredDeep : Symbol(RequiredDeep, Decl(deeplyNestedMappedTypes.ts, 8, 24))
76+
>A : Symbol(A, Decl(deeplyNestedMappedTypes.ts, 12, 64))
77+
78+
type D = RequiredDeep<B>;
79+
>D : Symbol(D, Decl(deeplyNestedMappedTypes.ts, 17, 25))
80+
>RequiredDeep : Symbol(RequiredDeep, Decl(deeplyNestedMappedTypes.ts, 8, 24))
81+
>B : Symbol(B, Decl(deeplyNestedMappedTypes.ts, 14, 44))
82+
83+
type Test1 = [C, D] extends [D, C] ? true : false; // false
84+
>Test1 : Symbol(Test1, Decl(deeplyNestedMappedTypes.ts, 18, 25))
85+
>C : Symbol(C, Decl(deeplyNestedMappedTypes.ts, 15, 64))
86+
>D : Symbol(D, Decl(deeplyNestedMappedTypes.ts, 17, 25))
87+
>D : Symbol(D, Decl(deeplyNestedMappedTypes.ts, 17, 25))
88+
>C : Symbol(C, Decl(deeplyNestedMappedTypes.ts, 15, 64))
89+
90+
type Test2 = C extends D ? true : false; // false
91+
>Test2 : Symbol(Test2, Decl(deeplyNestedMappedTypes.ts, 20, 50))
92+
>C : Symbol(C, Decl(deeplyNestedMappedTypes.ts, 15, 64))
93+
>D : Symbol(D, Decl(deeplyNestedMappedTypes.ts, 17, 25))
94+
95+
type Test3 = D extends C ? true : false; // false
96+
>Test3 : Symbol(Test3, Decl(deeplyNestedMappedTypes.ts, 21, 40))
97+
>D : Symbol(D, Decl(deeplyNestedMappedTypes.ts, 17, 25))
98+
>C : Symbol(C, Decl(deeplyNestedMappedTypes.ts, 15, 64))
99+
100+
// Simplified repro from #54246
101+
102+
// Except for the final non-recursive Record<K, V>, object types produced by NestedRecord all have the same symbol
103+
// and thus are considered deeply nested after three levels of nesting. Ideally we'd detect that recursion in this
104+
// type always terminates, but we're unaware of a general algorithm that accomplishes this.
105+
106+
type NestedRecord<K extends string, V> = K extends `${infer K0}.${infer KR}` ? { [P in K0]: NestedRecord<KR, V> } : Record<K, V>;
107+
>NestedRecord : Symbol(NestedRecord, Decl(deeplyNestedMappedTypes.ts, 22, 40))
108+
>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 30, 18))
109+
>V : Symbol(V, Decl(deeplyNestedMappedTypes.ts, 30, 35))
110+
>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 30, 18))
111+
>K0 : Symbol(K0, Decl(deeplyNestedMappedTypes.ts, 30, 59))
112+
>KR : Symbol(KR, Decl(deeplyNestedMappedTypes.ts, 30, 71))
113+
>P : Symbol(P, Decl(deeplyNestedMappedTypes.ts, 30, 82))
114+
>K0 : Symbol(K0, Decl(deeplyNestedMappedTypes.ts, 30, 59))
115+
>NestedRecord : Symbol(NestedRecord, Decl(deeplyNestedMappedTypes.ts, 22, 40))
116+
>KR : Symbol(KR, Decl(deeplyNestedMappedTypes.ts, 30, 71))
117+
>V : Symbol(V, Decl(deeplyNestedMappedTypes.ts, 30, 35))
118+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
119+
>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 30, 18))
120+
>V : Symbol(V, Decl(deeplyNestedMappedTypes.ts, 30, 35))
121+
122+
type Bar1 = NestedRecord<"x.y.z.a.b.c", number>;
123+
>Bar1 : Symbol(Bar1, Decl(deeplyNestedMappedTypes.ts, 30, 129))
124+
>NestedRecord : Symbol(NestedRecord, Decl(deeplyNestedMappedTypes.ts, 22, 40))
125+
126+
type Bar2 = NestedRecord<"x.y.z.a.b.c", string>;
127+
>Bar2 : Symbol(Bar2, Decl(deeplyNestedMappedTypes.ts, 32, 48))
128+
>NestedRecord : Symbol(NestedRecord, Decl(deeplyNestedMappedTypes.ts, 22, 40))
129+
130+
declare const bar1: Bar1;
131+
>bar1 : Symbol(bar1, Decl(deeplyNestedMappedTypes.ts, 35, 13))
132+
>Bar1 : Symbol(Bar1, Decl(deeplyNestedMappedTypes.ts, 30, 129))
133+
134+
const bar2: Bar2 = bar1; // Error expected
135+
>bar2 : Symbol(bar2, Decl(deeplyNestedMappedTypes.ts, 36, 5))
136+
>Bar2 : Symbol(Bar2, Decl(deeplyNestedMappedTypes.ts, 32, 48))
137+
>bar1 : Symbol(bar1, Decl(deeplyNestedMappedTypes.ts, 35, 13))
138+
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//// [tests/cases/compiler/deeplyNestedMappedTypes.ts] ////
2+
3+
=== deeplyNestedMappedTypes.ts ===
4+
// Simplified repro from #55535
5+
6+
type Id<T> = { [K in keyof T]: Id<T[K]> };
7+
>Id : Id<T>
8+
9+
type Foo1 = Id<{ x: { y: { z: { a: { b: { c: number } } } } } }>;
10+
>Foo1 : Id<{ x: { y: { z: { a: { b: { c: number; }; }; }; };}; }>
11+
>x : { y: { z: { a: { b: { c: number; }; }; };}; }
12+
>y : { z: { a: { b: { c: number; }; };}; }
13+
>z : { a: { b: { c: number; };}; }
14+
>a : { b: { c: number;}; }
15+
>b : { c: number; }
16+
>c : number
17+
18+
type Foo2 = Id<{ x: { y: { z: { a: { b: { c: string } } } } } }>;
19+
>Foo2 : Id<{ x: { y: { z: { a: { b: { c: string; }; }; }; };}; }>
20+
>x : { y: { z: { a: { b: { c: string; }; }; };}; }
21+
>y : { z: { a: { b: { c: string; }; };}; }
22+
>z : { a: { b: { c: string; };}; }
23+
>a : { b: { c: string;}; }
24+
>b : { c: string; }
25+
>c : string
26+
27+
declare const foo1: Foo1;
28+
>foo1 : Id<{ x: { y: { z: { a: { b: { c: number; }; }; }; }; }; }>
29+
30+
const foo2: Foo2 = foo1; // Error expected
31+
>foo2 : Id<{ x: { y: { z: { a: { b: { c: string; }; }; }; }; }; }>
32+
>foo1 : Id<{ x: { y: { z: { a: { b: { c: number; }; }; }; }; }; }>
33+
34+
// Repro from issue linked in #55535
35+
36+
type RequiredDeep<T> = { [K in keyof T]-?: RequiredDeep<T[K]> };
37+
>RequiredDeep : RequiredDeep<T>
38+
39+
type A = { a?: { b: { c: 1 | { d: 2000 } }}}
40+
>A : { a?: { b: { c: 1 | { d: 2000; };}; } | undefined; }
41+
>a : { b: { c: 1 | { d: 2000; };}; } | undefined
42+
>b : { c: 1 | { d: 2000;}; }
43+
>c : { d: 2000; } | 1
44+
>d : 2000
45+
46+
type B = { a?: { b: { c: { d: { e: { f: { g: 2 }}}}, x: 1000 }}}
47+
>B : { a?: { b: { c: { d: { e: { f: { g: 2; }; }; }; }; x: 1000;}; } | undefined; }
48+
>a : { b: { c: { d: { e: { f: { g: 2; }; }; }; }; x: 1000;}; } | undefined
49+
>b : { c: { d: { e: { f: { g: 2; }; }; };}; x: 1000; }
50+
>c : { d: { e: { f: { g: 2; }; };}; }
51+
>d : { e: { f: { g: 2; };}; }
52+
>e : { f: { g: 2;}; }
53+
>f : { g: 2; }
54+
>g : 2
55+
>x : 1000
56+
57+
type C = RequiredDeep<A>;
58+
>C : RequiredDeep<A>
59+
60+
type D = RequiredDeep<B>;
61+
>D : RequiredDeep<B>
62+
63+
type Test1 = [C, D] extends [D, C] ? true : false; // false
64+
>Test1 : false
65+
>true : true
66+
>false : false
67+
68+
type Test2 = C extends D ? true : false; // false
69+
>Test2 : false
70+
>true : true
71+
>false : false
72+
73+
type Test3 = D extends C ? true : false; // false
74+
>Test3 : false
75+
>true : true
76+
>false : false
77+
78+
// Simplified repro from #54246
79+
80+
// Except for the final non-recursive Record<K, V>, object types produced by NestedRecord all have the same symbol
81+
// and thus are considered deeply nested after three levels of nesting. Ideally we'd detect that recursion in this
82+
// type always terminates, but we're unaware of a general algorithm that accomplishes this.
83+
84+
type NestedRecord<K extends string, V> = K extends `${infer K0}.${infer KR}` ? { [P in K0]: NestedRecord<KR, V> } : Record<K, V>;
85+
>NestedRecord : NestedRecord<K, V>
86+
87+
type Bar1 = NestedRecord<"x.y.z.a.b.c", number>;
88+
>Bar1 : { x: { y: { z: { a: { b: Record<"c", number>; }; }; }; }; }
89+
90+
type Bar2 = NestedRecord<"x.y.z.a.b.c", string>;
91+
>Bar2 : { x: { y: { z: { a: { b: Record<"c", string>; }; }; }; }; }
92+
93+
declare const bar1: Bar1;
94+
>bar1 : { x: { y: { z: { a: { b: Record<"c", number>; }; }; }; }; }
95+
96+
const bar2: Bar2 = bar1; // Error expected
97+
>bar2 : { x: { y: { z: { a: { b: Record<"c", string>; }; }; }; }; }
98+
>bar1 : { x: { y: { z: { a: { b: Record<"c", number>; }; }; }; }; }
99+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// Simplified repro from #55535
5+
6+
type Id<T> = { [K in keyof T]: Id<T[K]> };
7+
8+
type Foo1 = Id<{ x: { y: { z: { a: { b: { c: number } } } } } }>;
9+
type Foo2 = Id<{ x: { y: { z: { a: { b: { c: string } } } } } }>;
10+
11+
declare const foo1: Foo1;
12+
const foo2: Foo2 = foo1; // Error expected
13+
14+
// Repro from issue linked in #55535
15+
16+
type RequiredDeep<T> = { [K in keyof T]-?: RequiredDeep<T[K]> };
17+
18+
type A = { a?: { b: { c: 1 | { d: 2000 } }}}
19+
type B = { a?: { b: { c: { d: { e: { f: { g: 2 }}}}, x: 1000 }}}
20+
21+
type C = RequiredDeep<A>;
22+
type D = RequiredDeep<B>;
23+
24+
type Test1 = [C, D] extends [D, C] ? true : false; // false
25+
type Test2 = C extends D ? true : false; // false
26+
type Test3 = D extends C ? true : false; // false
27+
28+
// Simplified repro from #54246
29+
30+
// Except for the final non-recursive Record<K, V>, object types produced by NestedRecord all have the same symbol
31+
// and thus are considered deeply nested after three levels of nesting. Ideally we'd detect that recursion in this
32+
// type always terminates, but we're unaware of a general algorithm that accomplishes this.
33+
34+
type NestedRecord<K extends string, V> = K extends `${infer K0}.${infer KR}` ? { [P in K0]: NestedRecord<KR, V> } : Record<K, V>;
35+
36+
type Bar1 = NestedRecord<"x.y.z.a.b.c", number>;
37+
type Bar2 = NestedRecord<"x.y.z.a.b.c", string>;
38+
39+
declare const bar1: Bar1;
40+
const bar2: Bar2 = bar1; // Error expected

0 commit comments

Comments
 (0)