zod icon indicating copy to clipboard operation
zod copied to clipboard

Implement `.remap()` on `ZodObject`

Open colinhacks opened this issue 3 months ago • 3 comments

The ability to modify the fields of a ZodObject schema as a function of the current fields is a much requested feature. This PR implements a new method .remap() to enable this.

  • https://github.com/colinhacks/zod/issues/2644
  • https://github.com/colinhacks/zod/issues/2891
  • https://github.com/colinhacks/zod/pull/2471

Given a simple initial schema...

const User = z.object({
  name: z.string(),
  age: z.number(),
});

...this method overwrites the existing fields as a function of the current shape.

const ModUser = User.remap((shape) => ({
  name: shape.name.optional(),
  age: shape.age.nullable(),
}));

type ModUser = z.infer<typeof ModUser>;
// { name?: string; age: number | null; }

Or it can use string literals to remap keys.

const ModUser = User.remap(() => ({
  name: "fullname",
  age: "newage",
}));

type ModUser = z.infer<typeof ModUser>;
// { fullname: string; newage: number; }

These can be mixed as well:

const ModUser = User.remap((shape) => ({
  name: "fullname",
  age: shape.age.optional(),
}));

For simplicity a plain object syntax is supported as well.

const ModUser = User.remap({
  name: "fullname",
  age: User.shape.age.optional(),
});

type ModUser = z.infer<typeof ModUser>;
// { fullname: string; age?: number; }

colinhacks avatar Apr 18 '24 07:04 colinhacks

Deploy Preview for guileless-rolypoly-866f8a ready!

Name Link
Latest commit 62b07154fbe9f1f007fdf922b6ecfc5d6b0c9583
Latest deploy log https://app.netlify.com/sites/guileless-rolypoly-866f8a/deploys/662fffe273af260008db49c2
Deploy Preview https://deploy-preview-3415--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 configuration.

netlify[bot] avatar Apr 18 '24 07:04 netlify[bot]

Thanks for this contribution @colinhacks. Curious to know what .remap adds vs .transform it's not straighforward to me. Perhaps I was mistakenly using .transform as mapper and .remap does exactly that whereas .transform is more field oriented ?

iiAku avatar Apr 18 '24 07:04 iiAku

Curious to know what .remap adds vs .transform it's not straighforward to me

The .transform() method lets you transform the data and returns a ZodEffects instance. The .remap() is for modifying the schema itself — it returns a new ZodObject with a modified shape (set of fields). It's a way to create variants of existing schemas.

Though this potential for confusion is interesting and worth taking into consideration. I'm not married to the name .remap() necessarily, so if anyone has suggestions that seem less ambiguous please chime in.

colinhacks avatar Apr 18 '24 07:04 colinhacks

So I actually think the ambiguity pointed out by @iiAku is kind of a fatal flaw. I also think .remap() would be more valuable as a post-parse transform anyway, as opposed to something that behaves more like .extend(). I'm going to close for now and re-evaluate.

colinhacks avatar May 03 '24 00:05 colinhacks