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

Recursion in Schemas #98

Closed
devcaeg opened this issue Aug 13, 2023 · 6 comments
Closed

Recursion in Schemas #98

devcaeg opened this issue Aug 13, 2023 · 6 comments
Assignees
Labels
question Further information is requested

Comments

@devcaeg
Copy link

devcaeg commented Aug 13, 2023

Hello @fabian-hiller,

I am trying to create the following schemas using Valibot, but it's not working properly. When I do it, TypeScript produces errors, causing both the User schema and the UserUsername schema to have the 'any' type. Can you show me the correct way to handle recursion? I've tried several approaches and can't seem to fix it.

import { array, merge, object, recursive } from 'valibot';

import { Base } from 'entities/base.entity';
import { UserUsername } from 'modules/users/entities/user-username.entity';

export const User = merge([
  Base,
  object({
    usernames: recursive(() => array(UserUsername)),
  }),
]);
import { merge, object, string } from 'valibot';

import { Base } from 'entities/base.entity';
import { User } from 'modules/users/entities/user.entity';

export const UserUsername = merge([
  Base,
  object({
    user: User,
    username: string(),
  }),
]);
@fabian-hiller
Copy link
Owner

Valibot works similar to Zod here. Maybe this helps: https://zod.dev/?id=recursive-types

@fabian-hiller fabian-hiller self-assigned this Aug 13, 2023
@fabian-hiller fabian-hiller added the question Further information is requested label Aug 13, 2023
@devcaeg devcaeg closed this as completed Aug 14, 2023
@pn-wiseverge
Copy link

pn-wiseverge commented Sep 13, 2023

Hi @devcaeg , did you manage to do it?

I have an object for breadcrumbs that can be like this:

{
  name: 'First level',
  url: 'http://github.com',
  children: {
      name: 'Second level',
      url: 'http://github.com',
      children: {
          name: 'Third level',
          url: 'http://github.com',
          children: {
              name: 'Forth level',
              url: 'http://github.com',
              children: {
                  ...
              }
          }
      }
  }
}

And I'm not being able to validate it.

@fabian-hiller
Copy link
Owner

Here is an example:

import { object, url, recursive, string } from 'valibot';

const Schema = object({
  name: string(),
  url: string([url()]),
  children: recursive(() => Schema),
});

@pn-wiseverge
Copy link

pn-wiseverge commented Sep 14, 2023

That returns me this TS error:

'Schema' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)

It appear to be because it reference itself. Shouldn't it? Maybe it can be some TS Config. Here is mine:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "jsxImportSource": "@emotion/react",
    "baseUrl": ".",
    "paths": {
      "src/*": ["src/*"]
    }
  },
  "typeAcquisition": { "enable": true },
  "exclude": ["node_modules"],
  "include": ["src/**/*.ts", "src/**/*.tsx"]
}

@fabian-hiller
Copy link
Owner

This is not preventable. You have to define the type yourself in this case, as described in the Zod docs. https://zod.dev/?id=recursive-types

@pn-wiseverge
Copy link

pn-wiseverge commented Sep 14, 2023

Many thanks for the help!!

I must say that typing with validbot is much easier than zod. Great work!!

It worked like this:

import { BaseSchema, object, optional, recursive, string } from 'valibot';

type BreadcrumbsSchema = {
  name: string;
  url?: string;
  parent?: BreadcrumbsSchema;
};

export const breadcrumbsSchema: BaseSchema<BreadcrumbsSchema> = object({
  name: string(),
  url: optional(string()),
  parent: recursive(() => optional(breadcrumbsSchema)),
});

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

No branches or pull requests

3 participants