Skip to content

feat: create recordWithPatterns schema #1165

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

EskiMojo14
Copy link
Contributor

@EskiMojo14 EskiMojo14 commented Apr 20, 2025

fixes #1159

const Schema = v.recordWithPatterns(
  [
    [
      v.pipe(v.string(), v.regex(/^foo\(.+\)$/)),
      v.pipe(v.string(), v.maxLength(1)),
    ],
    [
      v.pipe(v.string(), v.regex(/^bar\(.+\)$/)),
      v.pipe(v.string(), v.maxLength(10)),
    ],
  ],
  v.number(),
);

Also includes proper index signatures for strongly typed keys, e.g.

const FooKeySchema = v.custom<`foo(${string}`>(
  (arg) => typeof arg === "string" && /^foo\(.+\)$/.test(arg),
);

const Schema = v.recordWithPatterns([[FooKeySchema, v.string()]], v.number());

const parsed = v.parse(Schema, { "foo(x)": "x", x: 1 });

parsed["foo(x)"]; // string
parsed.x; // number

Copy link

vercel bot commented Apr 20, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
valibot ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 22, 2025 10:11am

@EskiMojo14 EskiMojo14 marked this pull request as ready for review April 21, 2025 22:26
@fabian-hiller
Copy link
Owner

Thank you for creating this PR! Do you know if Zod offers such a schema? How about calling it recordWithPatterns or templateRecord to better match our record schema? Is the second argument, the wildcard schema, necessary? Maybe it simplifies the API if we ask users to add this to the first argument.

@EskiMojo14
Copy link
Contributor Author

Do you know if Zod offers such a schema?

not to my knowledge, no - JSON schema has patternProperties which is similar

How about calling it recordWithPatterns or templateRecord to better match our record schema?

sure, makes sense

Is the second argument, the wildcard schema, necessary? Maybe it simplifies the API if we ask users to add this to the first argument.

what would be the desired behaviour if a key doesn't match any of the patterns?

@EskiMojo14
Copy link
Contributor Author

EskiMojo14 commented Apr 22, 2025

Ah, the rest argument is necessary, because these two types behave differently:

type Unmerged = {
    [key: `foo(${string})`]: string;
    [key: `bar(${string})`]: number;
} & {
    [key: string]: boolean;
}

type Merged = {
    [key: `foo(${string})`]: string;
    [key: `bar(${string})`]: number;
    [key: string]: boolean;
}

in Merged, the string index signature overrides all of the others.

edit: hmm, the below works, so we could just avoid calling Prettify to merge the intersection:

type Unmerged = {
    [key: `foo(${string})`]: string;
} & {
    [key: `bar(${string})`]: number;
} & {
    [key: string]: boolean;
}

it's kinda ugly, but 🤷🏻

@EskiMojo14 EskiMojo14 changed the title feat: create objectWithPatterns schema feat: create recordWithPatterns schema Apr 22, 2025
@EskiMojo14
Copy link
Contributor Author

EskiMojo14 commented Apr 22, 2025

that does still leave the question of what to do when a key doesn't match any of the patterns:

const parsed = v.parse(
  v.recordWithPatterns([
    [v.pipe(v.string(), v.startsWith("foo-")), v.string()],
  ]),
  { "foo-allowed": "hi", notAllowed: true },
);
// loose - { 'foo-allowed': 'hi', notAllowed: true }
// strip - { 'foo-allowed': 'hi' }
// strict - error
// rest - validate against rest, error if not match

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

Successfully merging this pull request may close these issues.

Validate value based on key format
2 participants