colinhacks / zod

TypeScript-first schema validation with static type inference
https://zod.dev
MIT License
33.09k stars 1.15k forks source link

variadic rest in the tuple with min & max capability #3708

Open ram2104 opened 1 month ago

ram2104 commented 1 month ago

I have a scenario, where I need to define the schema in the form of a tuple with certain restrictions in length of min, and max on the variadic rest.

const TypeOneSchema = z.object({
  name: z.string(),
  value: z.number(),
});

const TypeTwoSchema = z.object({
  title: z.string(),
  amount: z.number(),
});

const TupleSchema = z.tuple([
  TypeOneSchema, **// First element: TypeOneSchema**
  z.array(TypeTwoSchema).min(1).max(3) **// Rest elements: 1 to 3 TypeTwoSchema**
]);
Note: The above syntax of the tuple isn't supported, adding it here for a better understanding of the use case.

Say something like this: For example: the scenario is that a tuple can be a minimum of 2 items & at max, it can have 4 items in the array.

// Example usage

Valid

const validTuple1 = [ { name: 'John', value: 20 }, { title: 'Title 1', amount: 100 } ];

const validTuple2 = [ { name: 'John', value: 20 }, { title: 'Title 1', amount: 100 }, { title: 'Title 2', amount: 150 } ];

Invalid

const invalidTuple1 = [ {name: 'John', value: 20 } ];

const invalidTuple2 = [ { name: 'John', value: 20 }, { title: 'Title 1', amount: 100 }, { title: 'Title 2', amount: 150 }, { title: 'Title 3', amount: 200 }, ];

Please suggest how to achieve this using tuple, because it also gives the benefit of auto-suggestion in the code-editor.

sunnylost commented 2 weeks ago

I'll provide an idea: first, define a tuple(typeA, ...typeB). This way, you can handle the first type and the remaining types. As for the length restriction, you can use an array, but the array only deals with the count, so the values handled by min() and max() need to be increased by one.

const TupleSchema = z
  .tuple([TypeOneSchema])
  .rest(TypeTwoSchema)
  .and(z.array(z.any()).min(2).max(4)); // not 1 and 3