zod icon indicating copy to clipboard operation
zod copied to clipboard

feat(#1690): Add `ZodRequired`

Open santosmarco-caribou opened this issue 2 years ago • 8 comments

Closes #1690

This PR adds the ZodRequired type, which removes any undefined from both the schema's output and input.

~Note: I couldn't add .required() to the root ZodType class because it conflicts with the .required() method of ZodObject. Suggestions are welcome. I feel like it should live in the root ZodType class...~

santosmarco-caribou avatar Dec 22 '22 07:12 santosmarco-caribou

Deploy Preview for guileless-rolypoly-866f8a ready!

Built without sensitive environment variables

Name Link
Latest commit 93b89968026404b2b2e4a5223b43f25705ce2681
Latest deploy log https://app.netlify.com/sites/guileless-rolypoly-866f8a/deploys/63a50e1f2c78fd0009d94987
Deploy Preview https://deploy-preview-1738--guileless-rolypoly-866f8a.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

netlify[bot] avatar Dec 22 '22 07:12 netlify[bot]

@santosmarco-caribou looks good at a glance!

I haven't taken an in depth look - but I wonder if, for the sake of keeping .required() on the root ZodType, it would be possible to bring in the specific ZodObject funtionality at the top ZodType so that there's no confilct in the namespace? or via a _required() on the ZodObject with a instanceof check at the ZodType level? Just some ideas.

maxArturo avatar Dec 22 '22 12:12 maxArturo

@santosmarco-caribou looks good at a glance!

I haven't taken an in depth look - but I wonder if, for the sake of keeping .required() on the root ZodType, it would be possible to bring in the specific ZodObject funtionality at the top ZodType so that there's no confilct in the namespace? or via a _required() on the ZodObject with a instanceof check at the ZodType level? Just some ideas.

I'm afraid it isn't possible to bring the ZodObject logic up to the root ZodType class since the return type depends on the schema, unknownKeys, and catchall, which ZodType does not have access to.

santosmarco-caribou avatar Dec 22 '22 14:12 santosmarco-caribou

@MaxArturo

I came up with a solution using overloads. Don't know if that's the best way to handle this, but well, it works, passes all tests, and does not create any conflict.

Screenshot 2022-12-22 at 11 22 06 AM

santosmarco-caribou avatar Dec 22 '22 14:12 santosmarco-caribou

Very neat! Good job @santosmarco . To be sure, it would be a good idea to add tests that flex the interaction of ZodObject with .require() specifically, I think we're missing those.

maxArturo avatar Dec 22 '22 17:12 maxArturo

Very neat! Good job @santosmarco . To be sure, it would be a good idea to add tests that flex the interaction of ZodObject with .require() specifically, I think we're missing those.

@maxArturo Thanks. I've added additional tests specifically for ZodObject's .required() and everything looks OK.

I've also updated the .required() logic, return types, and removed deoptional (no longer needed) :)

santosmarco-caribou avatar Dec 23 '22 02:12 santosmarco-caribou

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar May 10 '23 00:05 stale[bot]

On further reflection, I think Zod should possibly consider generalizing this to ZodExclude. Though I'm still on the fence about whether this is a good idea.

Note that the types in this PR are technically wrong. For instance, if .required() behaved as implemented in this PR, the following schema would have Output type string, when it should be string | undefined.

z.string().transform(val => Math.random() > 0.5 ? val : undefined).required()

There's some inherent ambiguity here, which is why I've been hesistant to merge this. The open question is this: does the "required" check happen before or after the innerType parsing? I think different people will have different expectations about how this should work, unfortunately.

colinhacks avatar May 08 '24 19:05 colinhacks

I'm going to close this for now, but I'll keep this in mind over the development cycle for Zod 4. I need to do some restructuring and see if a more natural API emerges for making object schemas required (which is the fundamental issue solved by this PR). I also need to think more about how this will interact with Zod 4's new approach to exactOptionalPropertyTypes. I'll re-open if I decide to go ahead with ZodRequired. Thanks for the great work Marco 🙌

colinhacks avatar May 09 '24 06:05 colinhacks