Skip to content

Add an extra test for excess property check for intersection containing a recursive type #53100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(39,9):
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(86,11): error TS2322: Type '{ name: string; children: { name: string; children: { name: string; }[]; }[]; }' is not assignable to type 'User'.
Object literal may only specify known properties, and 'children' does not exist in type 'User'.
tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(102,35): error TS2339: Property 'children' does not exist on type 'User'.


==== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts (4 errors) ====
==== tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts (6 errors) ====
// repro from #44750

type Request = { l1: { l2: boolean } };
Expand Down Expand Up @@ -81,4 +84,56 @@ tests/cases/compiler/excessPropertyCheckIntersectionWithRecursiveType.ts(52,9):
},
},
}

// repro from #40405

type Length<T extends any[]> = T["length"];
type Prepend<V, T extends any[]> = ((head: V, ...args: T) => void) extends (
...args: infer R
) => void
? R
: any;

type BuildTree<T, N extends number = -1, I extends any[] = []> = {
1: T;
0: T & { children: BuildTree<T, N, Prepend<any, I>>[] };
}[Length<I> extends N ? 1 : 0];

interface User {
name: string;
}

type GrandUser = BuildTree<User, 2>;

const grandUser: GrandUser = {
name: "Grand User",
children: [
{
name: "Son",
children: [
{
name: "Grand son",
children: [
~~~~~~~~
!!! error TS2322: Type '{ name: string; children: { name: string; children: { name: string; }[]; }[]; }' is not assignable to type 'User'.
!!! error TS2322: Object literal may only specify known properties, and 'children' does not exist in type 'User'.
{
name: "123",
children: [
{
name: "Some other name",
},
],
},
],
},
],
},
],
};

grandUser.children[0].children[0].children[0];
~~~~~~~~
!!! error TS2339: Property 'children' does not exist on type 'User'.


Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,115 @@ export const schemaObj4: Schema4<Request> = {
},
}

// repro from #40405

type Length<T extends any[]> = T["length"];
>Length : Symbol(Length, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 55, 1))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 59, 12))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 59, 12))

type Prepend<V, T extends any[]> = ((head: V, ...args: T) => void) extends (
>Prepend : Symbol(Prepend, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 59, 43))
>V : Symbol(V, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 13))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 15))
>head : Symbol(head, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 37))
>V : Symbol(V, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 13))
>args : Symbol(args, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 45))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 15))

...args: infer R
>args : Symbol(args, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 60, 76))
>R : Symbol(R, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 61, 16))

) => void
? R
>R : Symbol(R, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 61, 16))

: any;

type BuildTree<T, N extends number = -1, I extends any[] = []> = {
>BuildTree : Symbol(BuildTree, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 64, 8))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 15))
>N : Symbol(N, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 17))
>I : Symbol(I, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 40))

1: T;
>1 : Symbol(1, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 66))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 15))

0: T & { children: BuildTree<T, N, Prepend<any, I>>[] };
>0 : Symbol(0, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 67, 7))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 15))
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
>BuildTree : Symbol(BuildTree, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 64, 8))
>T : Symbol(T, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 15))
>N : Symbol(N, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 17))
>Prepend : Symbol(Prepend, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 59, 43))
>I : Symbol(I, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 40))

}[Length<I> extends N ? 1 : 0];
>Length : Symbol(Length, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 55, 1))
>I : Symbol(I, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 40))
>N : Symbol(N, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 66, 17))

interface User {
>User : Symbol(User, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 69, 31))

name: string;
>name : Symbol(User.name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 71, 16))
}

type GrandUser = BuildTree<User, 2>;
>GrandUser : Symbol(GrandUser, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 73, 1))
>BuildTree : Symbol(BuildTree, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 64, 8))
>User : Symbol(User, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 69, 31))

const grandUser: GrandUser = {
>grandUser : Symbol(grandUser, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 77, 5))
>GrandUser : Symbol(GrandUser, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 73, 1))

name: "Grand User",
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 77, 30))

children: [
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 78, 21))
{
name: "Son",
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 80, 5))

children: [
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 81, 18))
{
name: "Grand son",
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 83, 9))

children: [
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 84, 28))
{
name: "123",
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 86, 13))

children: [
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 87, 26))
{
name: "Some other name",
>name : Symbol(name, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 89, 17))

},
],
},
],
},
],
},
],
};

grandUser.children[0].children[0].children[0];
>grandUser.children[0].children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
>grandUser.children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
>grandUser : Symbol(grandUser, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 77, 5))
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))
>children : Symbol(children, Decl(excessPropertyCheckIntersectionWithRecursiveType.ts, 68, 10))


Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,116 @@ export const schemaObj4: Schema4<Request> = {
},
}

// repro from #40405

type Length<T extends any[]> = T["length"];
>Length : Length<T>

type Prepend<V, T extends any[]> = ((head: V, ...args: T) => void) extends (
>Prepend : [head: V, ...args: T]
>head : V
>args : T

...args: infer R
>args : R

) => void
? R
: any;

type BuildTree<T, N extends number = -1, I extends any[] = []> = {
>BuildTree : BuildTree<T, N, I>
>-1 : -1
>1 : 1

1: T;
>1 : T

0: T & { children: BuildTree<T, N, Prepend<any, I>>[] };
>0 : T & { children: BuildTree<T, N, Prepend<any, I>>[]; }
>children : BuildTree<T, N, [head: any, ...args: I]>[]

}[Length<I> extends N ? 1 : 0];

interface User {
name: string;
>name : string
}

type GrandUser = BuildTree<User, 2>;
>GrandUser : User & { children: (User & { children: User[]; })[]; }

const grandUser: GrandUser = {
>grandUser : User & { children: (User & { children: User[]; })[]; }
>{ 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; }[]; }[]; }[]; }[]; }

name: "Grand User",
>name : string
>"Grand User" : "Grand User"

children: [
>children : { name: string; children: { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]; }[]
>[ { 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; }[]; }[]; }[]; }[]
{
>{ 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; }[]; }[]; }[]; }

name: "Son",
>name : string
>"Son" : "Son"

children: [
>children : { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]
>[ { name: "Grand son", children: [ { name: "123", children: [ { name: "Some other name", }, ], }, ], }, ] : { name: string; children: { name: string; children: { name: string; }[]; }[]; }[]
{
>{ name: "Grand son", children: [ { name: "123", children: [ { name: "Some other name", }, ], }, ], } : { name: string; children: { name: string; children: { name: string; }[]; }[]; }

name: "Grand son",
>name : string
>"Grand son" : "Grand son"

children: [
>children : { name: string; children: { name: string; }[]; }[]
>[ { name: "123", children: [ { name: "Some other name", }, ], }, ] : { name: string; children: { name: string; }[]; }[]
{
>{ name: "123", children: [ { name: "Some other name", }, ], } : { name: string; children: { name: string; }[]; }

name: "123",
>name : string
>"123" : "123"

children: [
>children : { name: string; }[]
>[ { name: "Some other name", }, ] : { name: string; }[]
{
>{ name: "Some other name", } : { name: string; }

name: "Some other name",
>name : string
>"Some other name" : "Some other name"

},
],
},
],
},
],
},
],
};

grandUser.children[0].children[0].children[0];
>grandUser.children[0].children[0].children[0] : any
>grandUser.children[0].children[0].children : any
>grandUser.children[0].children[0] : User
>grandUser.children[0].children : User[]
>grandUser.children[0] : User & { children: User[]; }
>grandUser.children : (User & { children: User[]; })[]
>grandUser : User & { children: (User & { children: User[]; })[]; }
>children : (User & { children: User[]; })[]
>0 : 0
>children : User[]
>0 : 0
>children : any
>0 : 0


Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,50 @@ export const schemaObj4: Schema4<Request> = {
},
},
}

// repro from #40405

type Length<T extends any[]> = T["length"];
type Prepend<V, T extends any[]> = ((head: V, ...args: T) => void) extends (
...args: infer R
) => void
? R
: any;

type BuildTree<T, N extends number = -1, I extends any[] = []> = {
1: T;
0: T & { children: BuildTree<T, N, Prepend<any, I>>[] };
}[Length<I> extends N ? 1 : 0];

interface User {
name: string;
}

type GrandUser = BuildTree<User, 2>;

const grandUser: GrandUser = {
name: "Grand User",
children: [
{
name: "Son",
children: [
{
name: "Grand son",
children: [
{
name: "123",
children: [
{
name: "Some other name",
},
],
},
],
},
],
},
],
};

grandUser.children[0].children[0].children[0];