zod icon indicating copy to clipboard operation
zod copied to clipboard

feat(#1508): Add mergeDeep to ZodObject

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

This PR adds mergeDeep to ZodObject. It's now possible to merge two ZodObjects deeply.

The method follows the same rules as merge—keys of B have priority over those from A, and the B's unknownKeys and catchall schema are preserved.

const A = z.object({
  a: z.string(),
  b: z.object({
    c: z.string(),
    d: z.string(),
    e: z.object({
      f: z.string(),
      g: z.string(),
      h: z.string(),
    }),
  }),
});

const B = z.object({
  b: z.object({
    i: z.string(), // should add this prop deeply inside the shape's `b` key
    j: z.string(), // same
    e: z.object({ // does not completely overwrite this key; instead add properties to it.
      k: z.string(), // will be added
      l: z.string(), // will be added
      h: z.bigint(),  // Overwrite from string to bigint
    }),
  }),
});

const mergedDeep = A.mergeDeep(B);
Screenshot 2022-12-22 at 5 35 10 AM

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

Deploy Preview for guileless-rolypoly-866f8a ready!

Built without sensitive environment variables

Name Link
Latest commit 22dcd1a71630bf129e139736daff381b272278af
Latest deploy log https://app.netlify.com/sites/guileless-rolypoly-866f8a/deploys/63a416cc4b3f6e00073f97f2
Deploy Preview https://deploy-preview-1739--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 08:12 netlify[bot]

Just because it can be done doesn't mean it should. The logic in MergeZodObjectsDeep is too complicated and limited. I regret adding .deepPartial because it remains incomplete and confusing to people who think it will "just work" when you have something like this:

z.object({
  outer: z.object({
    inner: z.string()
  }).optional()
})

The logic (both in .deepPartial and in your PRisn't smart enough to properly handle the nestedZodOptional. In fact to be fully complete you'd need to account for every possible subclass of ZodTypewhich isn't possible because Zod is designed to be extensible! People can subclassZodType` if they want and create new schema types.

Anyway I'm very allergic to things like this since deepPartial and discriminatedUnion have been a huge burden and a point of confusion for a long time.

colinhacks avatar Dec 24 '22 06:12 colinhacks

Just because it can be done doesn't mean it should. The logic in MergeZodObjectsDeep is too complicated and limited. I regret adding .deepPartial because it remains incomplete and confusing to people who think it will "just work" when you have something like this:

z.object({
  outer: z.object({
    inner: z.string()
  }).optional()
})

The logic (both in .deepPartial and in your PRisn't smart enough to properly handle the nestedZodOptional. In fact to be fully complete you'd need to account for every possible subclass of ZodTypewhich isn't possible because Zod is designed to be extensible! People can subclassZodType` if they want and create new schema types.

Anyway I'm very allergic to things like this since deepPartial and discriminatedUnion have been a huge burden and a point of confusion for a long time.

Closing PR and no more deep things 😢 But your concern is totally valid.

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