zod icon indicating copy to clipboard operation
zod copied to clipboard

Feature request: `.deepStrict`

Open liammcdermott opened this issue 1 year ago • 7 comments

Like .deepPartial is to .partial it would be beneficial to have a .deepStrict function that ensures every level in an object, array, or tuple hierarchy is .strict.

For example, this code does not generate a ZodError:

const person = z
  .object({
    name: z.string(),
    meta: z.object({
      born: z.string(),
    }),
  })
  .strict();

person.parse({
  name: "bob dylan",
  meta: {
    born: "a place",
    extraKey: 61,
  },
});

With .deepStrict it would work like this:

const person = z
  .object({
    name: z.string(),
    meta: z.object({
      born: z.string(),
    }),
  })
  .deepStrict();

person.parse({
  name: "bob dylan",
  meta: {
    born: "a place",
    extraKey: 61,
  },
});
// => throws ZodError

liammcdermott avatar Sep 01 '22 21:09 liammcdermott

This is very hard to do in the static domain. Currently .deepPartial is very limited and error-prone for similar reasons. I'll leave this open but I recommend using z.strictObject if you want a shorthand for declaring lots of strict objects without needing a method.

colinhacks avatar Sep 06 '22 00:09 colinhacks

Thank you for considering this Colin, that's fair enough. Thank you for the reference to z.strictObject, I didn't see that, much nicer than calling .strict() on every object.

liammcdermott avatar Sep 06 '22 15:09 liammcdermott

When using Joi there is kind of a "global" option you can enable so that the strict feature will be applied recursively across all your objects by default. For sure it is a challenge to make such configuration reflect statically in the types but maybe it is a really good improvement to Zod to introduce such feature in runtime only at least.

Not sure about the implementation details but from the developer perspective it would be something like this:

schema.safeParse({
  deepStrict: true,
})

renatoargh avatar Sep 30 '22 15:09 renatoargh

Would be nice to have such deepStrict: true option to cover cases, when extra keys are not welcomed. Not only it would allow to define more clear schemas - without the need to add .strict() or use .strictObject() everywhere, but also support cases requested in #1449, when we need to use the same shared schemas in both ways - as strict and "normal" ones.

elmeister avatar Oct 02 '22 11:10 elmeister

Having the behaviour of the schema change based on the parsing seems like a mistake to me. There would be no way to account for it in conversion / translation and it could act inconsistently in different parts of the code with no compiler errors to show for it.

StefanTerdell avatar Oct 05 '22 05:10 StefanTerdell

As per received feedback - changed to .deepStrict() method in newly opened PR

const person = z
  .object({
    name: z.string(),
    meta: z.object({
      born: z.string(),
    }),
  })
  .deepStrict();

person.parse({
  name: "bob dylan",
  meta: {
    born: "a place",
    extraKey: 61,
  },
});
// => throws ZodError

elmeister avatar Oct 06 '22 16:10 elmeister