Add tests for excess property check for intersection containing a recursive type (#52063)

This commit is contained in:
Mateusz Burzyński 2023-01-10 01:02:17 +01:00 committed by GitHub
parent 6bedd1c227
commit 9b718d0a70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 478 additions and 0 deletions

View File

@ -0,0 +1,84 @@
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(13,9): error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: Schema1<boolean>; }'.
Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema1<boolean>; }'.
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>); }'.
Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }'.
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(39,9): error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: Schema3<boolean>; }'.
Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema3<boolean>; }'.
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>); }'.
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>); }'.
==== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts (4 errors) ====
// repro from #44750
type Request = { l1: { l2: boolean } };
type Example<T> = { ex?: T | null };
type Schema1<T> = (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema1<T[P]> }; }) & Example<T>;
export const schemaObj1: Schema1<Request> = {
props: {
l1: {
props: {
l2: { type: 'boolean' },
invalid: false,
~~~~~~~~~~~~~~
!!! error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: Schema1<boolean>; }'.
!!! error TS2322: Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema1<boolean>; }'.
!!! 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; }>'
},
},
},
}
type Schema2<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: { [P in keyof T]: Schema2<T[P]> }; } & Example<T>);
export const schemaObj2: Schema2<Request> = {
props: {
l1: {
props: {
l2: { type: 'boolean' },
invalid: false,
~~~~~~~~~~~~~~
!!! error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }'.
!!! 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>); }'.
!!! 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; }>'
},
},
},
}
type Schema3<T> = Example<T> & (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema3<T[P]> }; });
export const schemaObj3: Schema3<Request> = {
props: {
l1: {
props: {
l2: { type: 'boolean' },
invalid: false,
~~~~~~~~~~~~~~
!!! error TS2322: Type '{ l2: { type: "boolean"; }; invalid: false; }' is not assignable to type '{ l2: Schema3<boolean>; }'.
!!! error TS2322: Object literal may only specify known properties, and 'invalid' does not exist in type '{ l2: Schema3<boolean>; }'.
!!! 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; }>'
},
},
},
}
type Schema4<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: Example<T> & { [P in keyof T]: Schema4<T[P]> }; });
export const schemaObj4: Schema4<Request> = {
props: {
l1: {
props: {
l2: { type: 'boolean' },
invalid: false,
~~~~~~~~~~~~~~
!!! 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>); }'.
!!! 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>); }'.
!!! 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>); }; }'
},
},
},
}

View File

@ -0,0 +1,178 @@
=== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts ===
// repro from #44750
type Request = { l1: { l2: boolean } };
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 16))
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 22))
type Example<T> = { ex?: T | null };
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 13))
>ex : Symbol(ex, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 19))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 13))
type Schema1<T> = (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema1<T[P]> }; }) & Example<T>;
>Schema1 : Symbol(Schema1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 36))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 40))
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 63))
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 74))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
>Schema1 : Symbol(Schema1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 36))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 74))
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 5, 13))
export const schemaObj1: Schema1<Request> = {
>schemaObj1 : Symbol(schemaObj1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 7, 12))
>Schema1 : Symbol(Schema1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 3, 36))
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
props: {
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 7, 45))
l1: {
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 8, 10))
props: {
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 9, 9))
l2: { type: 'boolean' },
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 10, 14))
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 11, 13))
invalid: false,
>invalid : Symbol(invalid, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 11, 32))
},
},
},
}
type Schema2<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: { [P in keyof T]: Schema2<T[P]> }; } & Example<T>);
>Schema2 : Symbol(Schema2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 16, 1))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 40))
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 76))
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 87))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
>Schema2 : Symbol(Schema2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 16, 1))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 87))
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 18, 13))
export const schemaObj2: Schema2<Request> = {
>schemaObj2 : Symbol(schemaObj2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 20, 12))
>Schema2 : Symbol(Schema2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 16, 1))
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
props: {
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 20, 45))
l1: {
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 21, 10))
props: {
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 22, 9))
l2: { type: 'boolean' },
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 23, 14))
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 24, 13))
invalid: false,
>invalid : Symbol(invalid, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 24, 32))
},
},
},
}
type Schema3<T> = Example<T> & (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema3<T[P]> }; });
>Schema3 : Symbol(Schema3, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 29, 1))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 53))
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 76))
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 87))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
>Schema3 : Symbol(Schema3, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 29, 1))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 13))
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 31, 87))
export const schemaObj3: Schema3<Request> = {
>schemaObj3 : Symbol(schemaObj3, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 33, 12))
>Schema3 : Symbol(Schema3, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 29, 1))
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
props: {
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 33, 45))
l1: {
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 34, 10))
props: {
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 35, 9))
l2: { type: 'boolean' },
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 36, 14))
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 37, 13))
invalid: false,
>invalid : Symbol(invalid, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 37, 32))
},
},
},
}
type Schema4<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: Example<T> & { [P in keyof T]: Schema4<T[P]> }; });
>Schema4 : Symbol(Schema4, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 42, 1))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 40))
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 76))
>Example : Symbol(Example, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 2, 39))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 100))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
>Schema4 : Symbol(Schema4, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 42, 1))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 13))
>P : Symbol(P, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 44, 100))
export const schemaObj4: Schema4<Request> = {
>schemaObj4 : Symbol(schemaObj4, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 46, 12))
>Schema4 : Symbol(Schema4, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 42, 1))
>Request : Symbol(Request, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 0, 0))
props: {
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 46, 45))
l1: {
>l1 : Symbol(l1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 47, 10))
props: {
>props : Symbol(props, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 48, 9))
l2: { type: 'boolean' },
>l2 : Symbol(l2, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 49, 14))
>type : Symbol(type, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 50, 13))
invalid: false,
>invalid : Symbol(invalid, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 50, 32))
},
},
},
}

View File

@ -0,0 +1,157 @@
=== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts ===
// repro from #44750
type Request = { l1: { l2: boolean } };
>Request : { l1: { l2: boolean;}; }
>l1 : { l2: boolean; }
>l2 : boolean
type Example<T> = { ex?: T | null };
>Example : Example<T>
>ex : T | null | undefined
>null : null
type Schema1<T> = (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema1<T[P]> }; }) & Example<T>;
>Schema1 : Schema1<T>
>type : "boolean"
>props : { [P in keyof T]: Schema1<T[P]>; }
export const schemaObj1: Schema1<Request> = {
>schemaObj1 : Schema1<Request>
>{ props: { l1: { props: { l2: { type: 'boolean' }, invalid: false, }, }, },} : { props: { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }; }
props: {
>props : { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }
>{ l1: { props: { l2: { type: 'boolean' }, invalid: false, }, }, } : { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }
l1: {
>l1 : { props: { l2: { type: "boolean"; }; invalid: boolean; }; }
>{ props: { l2: { type: 'boolean' }, invalid: false, }, } : { props: { l2: { type: "boolean"; }; invalid: boolean; }; }
props: {
>props : { l2: { type: "boolean"; }; invalid: boolean; }
>{ l2: { type: 'boolean' }, invalid: false, } : { l2: { type: "boolean"; }; invalid: boolean; }
l2: { type: 'boolean' },
>l2 : { type: "boolean"; }
>{ type: 'boolean' } : { type: "boolean"; }
>type : "boolean"
>'boolean' : "boolean"
invalid: false,
>invalid : boolean
>false : false
},
},
},
}
type Schema2<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: { [P in keyof T]: Schema2<T[P]> }; } & Example<T>);
>Schema2 : Schema2<T>
>type : "boolean"
>props : { [P in keyof T]: Schema2<T[P]>; }
export const schemaObj2: Schema2<Request> = {
>schemaObj2 : { props: { l1: { props: { l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }; } & Example<{ l2: boolean; }>; }; } & Example<Request>
>{ props: { l1: { props: { l2: { type: 'boolean' }, invalid: false, }, }, },} : { props: { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }; }
props: {
>props : { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }
>{ l1: { props: { l2: { type: 'boolean' }, invalid: false, }, }, } : { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }
l1: {
>l1 : { props: { l2: { type: "boolean"; }; invalid: boolean; }; }
>{ props: { l2: { type: 'boolean' }, invalid: false, }, } : { props: { l2: { type: "boolean"; }; invalid: boolean; }; }
props: {
>props : { l2: { type: "boolean"; }; invalid: boolean; }
>{ l2: { type: 'boolean' }, invalid: false, } : { l2: { type: "boolean"; }; invalid: boolean; }
l2: { type: 'boolean' },
>l2 : { type: "boolean"; }
>{ type: 'boolean' } : { type: "boolean"; }
>type : "boolean"
>'boolean' : "boolean"
invalid: false,
>invalid : boolean
>false : false
},
},
},
}
type Schema3<T> = Example<T> & (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema3<T[P]> }; });
>Schema3 : Schema3<T>
>type : "boolean"
>props : { [P in keyof T]: Schema3<T[P]>; }
export const schemaObj3: Schema3<Request> = {
>schemaObj3 : Schema3<Request>
>{ props: { l1: { props: { l2: { type: 'boolean' }, invalid: false, }, }, },} : { props: { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }; }
props: {
>props : { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }
>{ l1: { props: { l2: { type: 'boolean' }, invalid: false, }, }, } : { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }
l1: {
>l1 : { props: { l2: { type: "boolean"; }; invalid: boolean; }; }
>{ props: { l2: { type: 'boolean' }, invalid: false, }, } : { props: { l2: { type: "boolean"; }; invalid: boolean; }; }
props: {
>props : { l2: { type: "boolean"; }; invalid: boolean; }
>{ l2: { type: 'boolean' }, invalid: false, } : { l2: { type: "boolean"; }; invalid: boolean; }
l2: { type: 'boolean' },
>l2 : { type: "boolean"; }
>{ type: 'boolean' } : { type: "boolean"; }
>type : "boolean"
>'boolean' : "boolean"
invalid: false,
>invalid : boolean
>false : false
},
},
},
}
type Schema4<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: Example<T> & { [P in keyof T]: Schema4<T[P]> }; });
>Schema4 : Schema4<T>
>type : "boolean"
>props : Example<T> & { [P in keyof T]: Schema4<T[P]>; }
export const schemaObj4: Schema4<Request> = {
>schemaObj4 : { props: Example<Request> & { l1: { props: Example<{ l2: boolean; }> & { l2: ({ type: "boolean"; } & Example<false>) | ({ type: "boolean"; } & Example<true>); }; }; }; }
>{ props: { l1: { props: { l2: { type: 'boolean' }, invalid: false, }, }, },} : { props: { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }; }
props: {
>props : { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }
>{ l1: { props: { l2: { type: 'boolean' }, invalid: false, }, }, } : { l1: { props: { l2: { type: "boolean"; }; invalid: boolean; }; }; }
l1: {
>l1 : { props: { l2: { type: "boolean"; }; invalid: boolean; }; }
>{ props: { l2: { type: 'boolean' }, invalid: false, }, } : { props: { l2: { type: "boolean"; }; invalid: boolean; }; }
props: {
>props : { l2: { type: "boolean"; }; invalid: boolean; }
>{ l2: { type: 'boolean' }, invalid: false, } : { l2: { type: "boolean"; }; invalid: boolean; }
l2: { type: 'boolean' },
>l2 : { type: "boolean"; }
>{ type: 'boolean' } : { type: "boolean"; }
>type : "boolean"
>'boolean' : "boolean"
invalid: false,
>invalid : boolean
>false : false
},
},
},
}

View File

@ -0,0 +1,59 @@
// @strict: true
// @noEmit: true
// repro from #44750
type Request = { l1: { l2: boolean } };
type Example<T> = { ex?: T | null };
type Schema1<T> = (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema1<T[P]> }; }) & Example<T>;
export const schemaObj1: Schema1<Request> = {
props: {
l1: {
props: {
l2: { type: 'boolean' },
invalid: false,
},
},
},
}
type Schema2<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: { [P in keyof T]: Schema2<T[P]> }; } & Example<T>);
export const schemaObj2: Schema2<Request> = {
props: {
l1: {
props: {
l2: { type: 'boolean' },
invalid: false,
},
},
},
}
type Schema3<T> = Example<T> & (T extends boolean ? { type: 'boolean'; } : { props: { [P in keyof T]: Schema3<T[P]> }; });
export const schemaObj3: Schema3<Request> = {
props: {
l1: {
props: {
l2: { type: 'boolean' },
invalid: false,
},
},
},
}
type Schema4<T> = (T extends boolean ? { type: 'boolean'; } & Example<T> : { props: Example<T> & { [P in keyof T]: Schema4<T[P]> }; });
export const schemaObj4: Schema4<Request> = {
props: {
l1: {
props: {
l2: { type: 'boolean' },
invalid: false,
},
},
},
}