Skip to content
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

Maximum call stack size exceeded. #750

Closed
liyofx opened this issue Feb 4, 2024 · 2 comments
Closed

Maximum call stack size exceeded. #750

liyofx opened this issue Feb 4, 2024 · 2 comments

Comments

@liyofx
Copy link

liyofx commented Feb 4, 2024

import { describe , test, expect} from "bun:test";
import { Type } from "@sinclair/typebox";
import { TypeCompiler } from '@sinclair/typebox/compiler'

const bookFindMany = () => Type.Object({
  select: Type.Optional(BookSelectObjectSchema()),
});

const UserSelectObjectSchema = () => Type.Object(
  {
    id: Type.Optional(Type.Boolean()),
    email: Type.Optional(Type.Boolean()),
    name: Type.Optional(Type.Boolean()),
    books: Type.Optional(
      Type.Union([Type.Optional(Type.Boolean()), Type.Optional(bookFindMany())]),
    ),
  },
  { additionalProperties: false,},
);

const UserArgsObjectSchema = () => Type.Object(
  {
    select: Type.Optional(UserSelectObjectSchema()),
  },
  { additionalProperties: false },
);
const BookSelectObjectSchema = () => Type.Object(
  {
    id: Type.Optional(Type.Boolean()),
    title: Type.Optional(Type.Boolean()),
    author: Type.Optional(
      Type.Union([Type.Optional(Type.Boolean()), Type.Optional(UserArgsObjectSchema())]),
    ),
    authorId: Type.Optional(Type.Boolean()),
  },
  { additionalProperties: false },
);

const userFindMany = () => Type.Object({
  select: Type.Optional(UserSelectObjectSchema()),
});

describe('', ()=>{
  test('', async ()=> {
    var select = {select: {id: true, name: true, email: true}};
    var typeCheck = TypeCompiler.Compile(userFindMany());

    var isVaild = typeCheck.Check(select);
    console.log(typeCheck.Errors(select).First());

    expect(isVaild).toBeTrue()
  })
});
# bun test test/generator1.test.ts
bun test v1.0.25 (a8ff7be6)

test/generator1.test.ts:
11 | function RegExpType(value) {
12 |     return new RegExp(value.source, value.flags);
13 | }
14 | function ObjectType(value) {
15 |     const clonedProperties = Object.getOwnPropertyNames(value).reduce((acc, key) => ({ ...acc, [key]: Visit(value[key]) }), {});
16 |     const clonedSymbols = Object.getOwnPropertySymbols(value).reduce((acc, key) => ({ ...acc, [key]: Visit(value[key]) }), {});
                                      ^
RangeError: Maximum call stack size exceeded.
      at /Users/z/Documents/web/prisma-zod-generator/node_modules/@sinclair/typebox/build/import/type/clone/value.mjs:16:34
      at reduce (:1:21)
      at ObjectType (/Users/z/Documents/web/prisma-zod-generator/node_modules/@sinclair/typebox/build/import/type/clone/value.mjs:15:30)
      at CloneType (/Users/z/Documents/web/prisma-zod-generator/node_modules/@sinclair/typebox/build/import/type/clone/type.mjs:8:17)
      at AddOptional (/Users/z/Documents/web/prisma-zod-generator/node_modules/@sinclair/typebox/build/import/type/optional/optional.mjs:10:17)
      at BookSelectObjectSchema (/Users/z/Documents/web/prisma-zod-generator/test/generator1.test.ts:31:9)
      at bookFindMany (/Users/z/Documents/web/prisma-zod-generator/test/generator1.test.ts:7:25)
      at UserSelectObjectSchema (/Users/z/Documents/web/prisma-zod-generator/test/generator1.test.ts:16:64)
      at UserArgsObjectSchema (/Users/z/Documents/web/prisma-zod-generator/test/generator1.test.ts:24:27)
      at BookSelectObjectSchema (/Users/z/Documents/web/prisma-zod-generator/test/generator1.test.ts:34:64)
✗ test [33.92ms]

 0 pass
 1 fail
Ran 1 tests across 1 files. [75.00ms]
@sinclairzx81
Copy link
Owner

@liyofx Hiya,

TypeBox does not support cyclic types. The issue here is that these type functions are cyclically initializing each other. You can reproduce the issue by calling the userFindMany() function only.

userFindMany() // results in a cyclic type

// userFindMany -> UserSelectObjectSchema -> 
//   bookFindMany -> BookSelectObjectSchema -> UserArgsObjectSchema -> UserSelectObjectSchema -> 
//   bookFindMany -> BookSelectObjectSchema -> UserArgsObjectSchema -> UserSelectObjectSchema -> 
//   bookFindMany -> BookSelectObjectSchema -> UserArgsObjectSchema -> UserSelectObjectSchema -> 
//   bookFindMany -> ...infinite

You can somewhat approach cyclic types using Type.Ref however cyclic type inference is not well supported in TypeBox (due to difficulties getting TypeScript to handle infinite instantiations). Additionally, cyclic, self referential values are non-serializable in JSON.

The recommendation for handling these types would be use either use Type.Ref or just explicitly implement a custom type and register via the TypeRegistry. Another approach may be to use a generic recursive type, but would likely require refactoring (or restructuring the type to support)

Will close off this issue as this functionality is currently not supported.
All the best
S

@liyofx
Copy link
Author

liyofx commented Feb 4, 2024

@sinclairzx81
I tried Type.Ref, but it still didn't work. I hope you can give me a simple example. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants