Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a way to make default interop with null values #3955

Open
remcohaszing opened this issue Jan 22, 2025 · 0 comments
Open

Provide a way to make default interop with null values #3955

remcohaszing opened this issue Jan 22, 2025 · 0 comments

Comments

@remcohaszing
Copy link

I have some schemas where I want to accept null as input, and turn that into a default value. I’m generating JSON schemas and documentation from the zod schemas, so the actual .default('default') call is important to set metadata.

Let’s say this is the base schema. I would like this script to log default twice.

const schema = z
  .enum(['default', 'custom'])
  .nullish()
  .default('default')

console.log(schema.parse(null))
console.log(schema.parse(undefined))

I could do the following:

const schema = z
  .enum(['default', 'custom'])
  .nullish()
  .default('default')
  .transform((input, ctx) => input == null ? 'devault', input)

console.log(schema.parse(null))
console.log(schema.parse(undefined))

This works ok. However, this is error prone. I made a typo in the returned value from transform. I also need to maintain the default value twice.

I see two solutions.

  1. .default() can accept a second argument. This is a function which returns whether or not the default value should be used.

    const schema = z
      .enum(['default', 'custom'])
      .nullish()
      .default('default', (input) => input == null)
  2. Provide more context to the .transform() context, notably a default value.

    const schema = z
      .enum(['default', 'custom'])
      .nullish()
      .default('default')
      .transform((input, ctx) => input == null ? ctx.default, input)

    This is especially useful, because it makes the transform function reusable.

    function setDefault<T>(input: T | null | undefined, ctx: z.RefinementCtx): T {
      return input == null ? z.default : input
    }
    
    const schema = z
      .enum(['default', 'custom'])
      .nullish()
      .default('default')
      .transform(setDefault)
    
    const anotherSchema = z
      .enum(['another default', 'another custom'])
      .nullish()
      .default('another default')
      .transform(setDefault)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant