Skip to content

Commit 9b718d0

Browse files
authored
Add tests for excess property check for intersection containing a recursive type (#52063)
1 parent 6bedd1c commit 9b718d0

4 files changed

+478
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(13,9): error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: Schema1<boolean>; }'.
2+
Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema1<boolean>; }'.
3+
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(26,9): error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }'.
4+
Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }'.
5+
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(39,9): error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: Schema3<boolean>; }'.
6+
Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema3<boolean>; }'.
7+
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>); }'.
8+
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+
10+
11+
==== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts (4 errors) ====
12+
// repro from #44750
13+
14+
type Request = { l1: { l2: boolean } };
15+
type Example<T> = { ex?: T | null };
16+
17+
type Schema1<T> = (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema1<T[P]> }; }) & Example<T>;
18+
19+
export const schemaObj1: Schema1<Request> = {
20+
props: {
21+
l1: {
22+
props: {
23+
l2: { type: 'boolean' },
24+
invalid: false,
25+
~~~~~~~~~~~~~~
26+
!!! error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: Schema1<boolean>; }'.
27+
!!! error TS2322: Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema1<boolean>; }'.
28+
!!! related TS6500 tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts:6:65: The expected type comes from property 'props' which is declared here on type 'Schema1<{ l2: boolean; }>'
29+
},
30+
},
31+
},
32+
}
33+
34+
type Schema2<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: { [P in keyof T]: Schema2<T[P]> }; } & Example<T>);
35+
36+
export const schemaObj2: Schema2<Request> = {
37+
props: {
38+
l1: {
39+
props: {
40+
l2: { type: 'boolean' },
41+
invalid: false,
42+
~~~~~~~~~~~~~~
43+
!!! error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }'.
44+
!!! error TS2322: Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }'.
45+
!!! related TS6500 tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts:19:78: The expected type comes from property 'props' which is declared here on type '{ props: { l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }; } & Example<{ l2: boolean; }>'
46+
},
47+
},
48+
},
49+
}
50+
51+
type Schema3<T> = Example<T> & (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema3<T[P]> }; });
52+
53+
export const schemaObj3: Schema3<Request> = {
54+
props: {
55+
l1: {
56+
props: {
57+
l2: { type: 'boolean' },
58+
invalid: false,
59+
~~~~~~~~~~~~~~
60+
!!! error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: Schema3<boolean>; }'.
61+
!!! error TS2322: Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema3<boolean>; }'.
62+
!!! related TS6500 tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts:32:78: The expected type comes from property 'props' which is declared here on type 'Schema3<{ l2: boolean; }>'
63+
},
64+
},
65+
},
66+
}
67+
68+
type Schema4<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: Example<T> & { [P in keyof T]: Schema4<T[P]> }; });
69+
70+
export const schemaObj4: Schema4<Request> = {
71+
props: {
72+
l1: {
73+
props: {
74+
l2: { type: 'boolean' },
75+
invalid: false,
76+
~~~~~~~~~~~~~~
77+
!!! 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>); }'.
78+
!!! error TS2322: 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>); }'.
79+
!!! related TS6500 tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts:45:78: The expected type comes from property 'props' which is declared here on type '{ props: Example<{ l2: boolean; }> & { l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }; }'
80+
},
81+
},
82+
},
83+
}
84+
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
=== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts ===
2+
// repro from #44750
3+
4+
type Request = { l1: { l2: boolean } };
5+
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
6+
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 16))
7+
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 22))
8+
9+
type Example<T> = { ex?: T | null };
10+
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
11+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 13))
12+
>ex : Symbol(ex, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 19))
13+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 13))
14+
15+
type Schema1<T> = (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema1<T[P]> }; }) & Example<T>;
16+
>Schema1 : Symbol(Schema1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 36))
17+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
18+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
19+
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 40))
20+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 63))
21+
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 74))
22+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
23+
>Schema1 : Symbol(Schema1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 36))
24+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
25+
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 74))
26+
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
27+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
28+
29+
export const schemaObj1: Schema1<Request> = {
30+
>schemaObj1 : Symbol(schemaObj1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 7, 12))
31+
>Schema1 : Symbol(Schema1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 36))
32+
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
33+
34+
props: {
35+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 7, 45))
36+
37+
l1: {
38+
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 8, 10))
39+
40+
props: {
41+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 9, 9))
42+
43+
l2: { type: 'boolean' },
44+
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 10, 14))
45+
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 11, 13))
46+
47+
invalid: false,
48+
>invalid : Symbol(invalid, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 11, 32))
49+
50+
},
51+
},
52+
},
53+
}
54+
55+
type Schema2<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: { [P in keyof T]: Schema2<T[P]> }; } & Example<T>);
56+
>Schema2 : Symbol(Schema2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 16, 1))
57+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
58+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
59+
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 40))
60+
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
61+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
62+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 76))
63+
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 87))
64+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
65+
>Schema2 : Symbol(Schema2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 16, 1))
66+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
67+
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 87))
68+
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
69+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
70+
71+
export const schemaObj2: Schema2<Request> = {
72+
>schemaObj2 : Symbol(schemaObj2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 20, 12))
73+
>Schema2 : Symbol(Schema2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 16, 1))
74+
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
75+
76+
props: {
77+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 20, 45))
78+
79+
l1: {
80+
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 21, 10))
81+
82+
props: {
83+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 22, 9))
84+
85+
l2: { type: 'boolean' },
86+
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 23, 14))
87+
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 24, 13))
88+
89+
invalid: false,
90+
>invalid : Symbol(invalid, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 24, 32))
91+
92+
},
93+
},
94+
},
95+
}
96+
97+
type Schema3<T> = Example<T> & (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema3<T[P]> }; });
98+
>Schema3 : Symbol(Schema3, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 29, 1))
99+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
100+
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
101+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
102+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
103+
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 53))
104+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 76))
105+
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 87))
106+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
107+
>Schema3 : Symbol(Schema3, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 29, 1))
108+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
109+
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 87))
110+
111+
export const schemaObj3: Schema3<Request> = {
112+
>schemaObj3 : Symbol(schemaObj3, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 33, 12))
113+
>Schema3 : Symbol(Schema3, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 29, 1))
114+
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
115+
116+
props: {
117+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 33, 45))
118+
119+
l1: {
120+
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 34, 10))
121+
122+
props: {
123+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 35, 9))
124+
125+
l2: { type: 'boolean' },
126+
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 36, 14))
127+
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 37, 13))
128+
129+
invalid: false,
130+
>invalid : Symbol(invalid, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 37, 32))
131+
132+
},
133+
},
134+
},
135+
}
136+
137+
type Schema4<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: Example<T> & { [P in keyof T]: Schema4<T[P]> }; });
138+
>Schema4 : Symbol(Schema4, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 42, 1))
139+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
140+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
141+
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 40))
142+
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
143+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
144+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 76))
145+
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
146+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
147+
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 100))
148+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
149+
>Schema4 : Symbol(Schema4, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 42, 1))
150+
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
151+
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 100))
152+
153+
export const schemaObj4: Schema4<Request> = {
154+
>schemaObj4 : Symbol(schemaObj4, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 46, 12))
155+
>Schema4 : Symbol(Schema4, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 42, 1))
156+
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
157+
158+
props: {
159+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 46, 45))
160+
161+
l1: {
162+
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 47, 10))
163+
164+
props: {
165+
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 48, 9))
166+
167+
l2: { type: 'boolean' },
168+
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 49, 14))
169+
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 50, 13))
170+
171+
invalid: false,
172+
>invalid : Symbol(invalid, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 50, 32))
173+
174+
},
175+
},
176+
},
177+
}
178+

0 commit comments

Comments
 (0)