Skip to content

Commit

Permalink
Add an extra test for excess property check for intersection containi…
Browse files Browse the repository at this point in the history
…ng a recursive type (#53100)
  • Loading branch information
Andarist authored Mar 8, 2023
1 parent 74a37f8 commit 615a97b
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 1 deletion.
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 @@ -154,3 +154,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];

0 comments on commit 615a97b

Please sign in to comment.