Skip to content

Commit 615a97b

Browse files
authored
Add an extra test for excess property check for intersection containing a recursive type (microsoft#53100)
1 parent 74a37f8 commit 615a97b

4 files changed

+328
-1
lines changed

tests/baselines/reference/excessPropertyCheckIntersectionWithRecursiveType.errors.txt

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(39,9):
66
Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema3<boolean>; }'.
77
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(52,9): error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type 'Example<{ l2: boolean; }> & { l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }'.
88
Object literal may only specify known properties, and 'invalid' does not exist in type 'Example<{ l2: boolean; }> & { l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }'.
9+
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(86,11): error TS2322: Type '{ name: string; children: { name: string; children: { name: string; }[]; }[]; }' is not assignable to type 'User'.
10+
Object literal may only specify known properties, and 'children' does not exist in type 'User'.
11+
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(102,35): error TS2339: Property 'children' does not exist on type 'User'.
912

1013

11-
==== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts (4 errors) ====
14+
==== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts (6 errors) ====
1215
// repro from #44750
1316

1417
type Request = { l1: { l2: boolean } };
@@ -81,4 +84,56 @@ tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(52,9):
8184
},
8285
},
8386
}
87+
88+
// repro from #40405
89+
90+
type Length<T extends any[]> = T["length"];
91+
type Prepend<V, T extends any[]> = ((head: V, ...args: T) => void) extends (
92+
...args: infer R
93+
) => void
94+
? R
95+
: any;
96+
97+
type BuildTree<T, N extends number = -1, I extends any[] = []> = {
98+
1: T;
99+
0: T & { children: BuildTree<T, N, Prepend<any, I>>[] };
100+
}[Length<I> extends N ? 1 : 0];
101+
102+
interface User {
103+
name: string;
104+
}
105+
106+
type GrandUser = BuildTree<User, 2>;
107+
108+
const grandUser: GrandUser = {
109+
name: "Grand User",
110+
children: [
111+
{
112+
name: "Son",
113+
children: [
114+
{
115+
name: "Grand son",
116+
children: [
117+
~~~~~~~~
118+
!!! error TS2322: Type '{ name: string; children: { name: string; children: { name: string; }[]; }[]; }' is not assignable to type 'User'.
119+
!!! error TS2322: Object literal may only specify known properties, and 'children' does not exist in type 'User'.
120+
{
121+
name: "123",
122+
children: [
123+
{
124+
name: "Some other name",
125+
},
126+
],
127+
},
128+
],
129+
},
130+
],
131+
},
132+
],
133+
};
134+
135+
grandUser.children[0].children[0].children[0];
136+
~~~~~~~~
137+
!!! error TS2339: Property 'children' does not exist on type 'User'.
138+
84139

tests/baselines/reference/excessPropertyCheckIntersectionWithRecursiveType.symbols

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,115 @@ export const schemaObj4: Schema4<Request> = {
176176
},
177177
}
178178

179+
// repro from #40405
180+
181+
type Length<T extends any[]> = T["length"];
182+
>Length : Symbol(Length, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 55, 1))
183+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 59, 12))
184+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 59, 12))
185+
186+
type Prepend<V, T extends any[]> = ((head: V, ...args: T) => void) extends (
187+
>Prepend : Symbol(Prepend, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 59, 43))
188+
>V : Symbol(V, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 13))
189+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 15))
190+
>head : Symbol(head, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 37))
191+
>V : Symbol(V, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 13))
192+
>args : Symbol(args, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 45))
193+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 15))
194+
195+
...args: infer R
196+
>args : Symbol(args, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 76))
197+
>R : Symbol(R, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 61, 16))
198+
199+
) => void
200+
? R
201+
>R : Symbol(R, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 61, 16))
202+
203+
: any;
204+
205+
type BuildTree<T, N extends number = -1, I extends any[] = []> = {
206+
>BuildTree : Symbol(BuildTree, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 64, 8))
207+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 15))
208+
>N : Symbol(N, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 17))
209+
>I : Symbol(I, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 40))
210+
211+
1: T;
212+
>1 : Symbol(1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 66))
213+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 15))
214+
215+
0: T & { children: BuildTree<T, N, Prepend<any, I>>[] };
216+
>0 : Symbol(0, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 67, 7))
217+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 15))
218+
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
219+
>BuildTree : Symbol(BuildTree, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 64, 8))
220+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 15))
221+
>N : Symbol(N, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 17))
222+
>Prepend : Symbol(Prepend, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 59, 43))
223+
>I : Symbol(I, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 40))
224+
225+
}[Length<I> extends N ? 1 : 0];
226+
>Length : Symbol(Length, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 55, 1))
227+
>I : Symbol(I, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 40))
228+
>N : Symbol(N, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 17))
229+
230+
interface User {
231+
>User : Symbol(User, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 69, 31))
232+
233+
name: string;
234+
>name : Symbol(User.name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 71, 16))
235+
}
236+
237+
type GrandUser = BuildTree<User, 2>;
238+
>GrandUser : Symbol(GrandUser, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 73, 1))
239+
>BuildTree : Symbol(BuildTree, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 64, 8))
240+
>User : Symbol(User, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 69, 31))
241+
242+
const grandUser: GrandUser = {
243+
>grandUser : Symbol(grandUser, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 77, 5))
244+
>GrandUser : Symbol(GrandUser, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 73, 1))
245+
246+
name: "Grand User",
247+
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 77, 30))
248+
249+
children: [
250+
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 78, 21))
251+
{
252+
name: "Son",
253+
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 80, 5))
254+
255+
children: [
256+
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 81, 18))
257+
{
258+
name: "Grand son",
259+
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 83, 9))
260+
261+
children: [
262+
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 84, 28))
263+
{
264+
name: "123",
265+
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 86, 13))
266+
267+
children: [
268+
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 87, 26))
269+
{
270+
name: "Some other name",
271+
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 89, 17))
272+
273+
},
274+
],
275+
},
276+
],
277+
},
278+
],
279+
},
280+
],
281+
};
282+
283+
grandUser.children[0].children[0].children[0];
284+
>grandUser.children[0].children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
285+
>grandUser.children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
286+
>grandUser : Symbol(grandUser, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 77, 5))
287+
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
288+
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
289+
290+

tests/baselines/reference/excessPropertyCheckIntersectionWithRecursiveType.types

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,116 @@ export const schemaObj4: Schema4<Request> = {
154154
},
155155
}
156156

157+
// repro from #40405
158+
159+
type Length<T extends any[]> = T["length"];
160+
>Length : Length<T>
161+
162+
type Prepend<V, T extends any[]> = ((head: V, ...args: T) => void) extends (
163+
>Prepend : [head: V, ...args: T]
164+
>head : V
165+
>args : T
166+
167+
...args: infer R
168+
>args : R
169+
170+
) => void
171+
? R
172+
: any;
173+
174+
type BuildTree<T, N extends number = -1, I extends any[] = []> = {
175+
>BuildTree : BuildTree<T, N, I>
176+
>-1 : -1
177+
>1 : 1
178+
179+
1: T;
180+
>1 : T
181+
182+
0: T & { children: BuildTree<T, N, Prepend<any, I>>[] };
183+
>0 : T & { children: BuildTree<T, N, Prepend<any, I>>[]; }
184+
>children : BuildTree<T, N, [head: any, ...args: I]>[]
185+
186+
}[Length<I> extends N ? 1 : 0];
187+
188+
interface User {
189+
name: string;
190+
>name : string
191+
}
192+
193+
type GrandUser = BuildTree<User, 2>;
194+
>GrandUser : User & { children: (User & { children: User[]; })[]; }
195+
196+
const grandUser: GrandUser = {
197+
>grandUser : User & { children: (User & { children: User[]; })[]; }
198+
>{ name: "Grand User", children: [ { name: "Son", children: [ { name: "Grand son", children: [ { name: "123", children: [ { name: "Some other name", }, ], }, ], }, ], }, ],} : { name: string; children: { name: string; children: { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]; }[]; }
199+
200+
name: "Grand User",
201+
>name : string
202+
>"Grand User" : "Grand User"
203+
204+
children: [
205+
>children : { name: string; children: { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]; }[]
206+
>[ { name: "Son", children: [ { name: "Grand son", children: [ { name: "123", children: [ { name: "Some other name", }, ], }, ], }, ], }, ] : { name: string; children: { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]; }[]
207+
{
208+
>{ name: "Son", children: [ { name: "Grand son", children: [ { name: "123", children: [ { name: "Some other name", }, ], }, ], }, ], } : { name: string; children: { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]; }
209+
210+
name: "Son",
211+
>name : string
212+
>"Son" : "Son"
213+
214+
children: [
215+
>children : { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]
216+
>[ { name: "Grand son", children: [ { name: "123", children: [ { name: "Some other name", }, ], }, ], }, ] : { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]
217+
{
218+
>{ name: "Grand son", children: [ { name: "123", children: [ { name: "Some other name", }, ], }, ], } : { name: string; children: { name: string; children: { name: string; }[]; }[]; }
219+
220+
name: "Grand son",
221+
>name : string
222+
>"Grand son" : "Grand son"
223+
224+
children: [
225+
>children : { name: string; children: { name: string; }[]; }[]
226+
>[ { name: "123", children: [ { name: "Some other name", }, ], }, ] : { name: string; children: { name: string; }[]; }[]
227+
{
228+
>{ name: "123", children: [ { name: "Some other name", }, ], } : { name: string; children: { name: string; }[]; }
229+
230+
name: "123",
231+
>name : string
232+
>"123" : "123"
233+
234+
children: [
235+
>children : { name: string; }[]
236+
>[ { name: "Some other name", }, ] : { name: string; }[]
237+
{
238+
>{ name: "Some other name", } : { name: string; }
239+
240+
name: "Some other name",
241+
>name : string
242+
>"Some other name" : "Some other name"
243+
244+
},
245+
],
246+
},
247+
],
248+
},
249+
],
250+
},
251+
],
252+
};
253+
254+
grandUser.children[0].children[0].children[0];
255+
>grandUser.children[0].children[0].children[0] : any
256+
>grandUser.children[0].children[0].children : any
257+
>grandUser.children[0].children[0] : User
258+
>grandUser.children[0].children : User[]
259+
>grandUser.children[0] : User & { children: User[]; }
260+
>grandUser.children : (User & { children: User[]; })[]
261+
>grandUser : User & { children: (User & { children: User[]; })[]; }
262+
>children : (User & { children: User[]; })[]
263+
>0 : 0
264+
>children : User[]
265+
>0 : 0
266+
>children : any
267+
>0 : 0
268+
269+

tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,50 @@ export const schemaObj4: Schema4<Request> = {
5757
},
5858
},
5959
}
60+
61+
// repro from #40405
62+
63+
type Length<T extends any[]> = T["length"];
64+
type Prepend<V, T extends any[]> = ((head: V, ...args: T) => void) extends (
65+
...args: infer R
66+
) => void
67+
? R
68+
: any;
69+
70+
type BuildTree<T, N extends number = -1, I extends any[] = []> = {
71+
1: T;
72+
0: T & { children: BuildTree<T, N, Prepend<any, I>>[] };
73+
}[Length<I> extends N ? 1 : 0];
74+
75+
interface User {
76+
name: string;
77+
}
78+
79+
type GrandUser = BuildTree<User, 2>;
80+
81+
const grandUser: GrandUser = {
82+
name: "Grand User",
83+
children: [
84+
{
85+
name: "Son",
86+
children: [
87+
{
88+
name: "Grand son",
89+
children: [
90+
{
91+
name: "123",
92+
children: [
93+
{
94+
name: "Some other name",
95+
},
96+
],
97+
},
98+
],
99+
},
100+
],
101+
},
102+
],
103+
};
104+
105+
grandUser.children[0].children[0].children[0];
106+

0 commit comments

Comments
 (0)