colinhacks / zod

TypeScript-first schema validation with static type inference
https://zod.dev
MIT License
33.09k stars 1.15k forks source link

Access, manipulate, and throw error from `z.catch` #3766

Open MMZK1526 opened 14 hours ago

MMZK1526 commented 14 hours ago

If I understand correctly, z.catch always catches all errors, and it is not possible to only catch on certain cases and rethrow the error in other cases.

For example, if I want an API_KEY to have a hardcoded default value only when the global variable env is "dev", I might do something like this:

...
"API_KEY": z.string()
  .catch(function () {
    if (env === "dev") return defaultValue;
  }).pipe(z.string()),
...

Note that I have to try to parse the entire result as a string again in the pipe, so that if I'm not in dev mode, the catch turns the key into undefined which fails the second z.string().

Ideally I would imagine being able to "rethrow" the error in the catch.

sunnylost commented 12 hours ago

catch is just like default, it'll always return valid parse. Allowing the catch to rethrow would change its semantics, and I’m not sure if the author would be willing to make such a change. For now, I suggest wrapping a utility method to achieve the same effect.

function addCatchInDev(schema: z.ZodType<any>, wrapper: () => any) {
  if (env === "dev") {
    return schema.catch(wrapper);
  }

  return schema;
}

const schema = addCatchInDev(z.string(), () => defaultValue);

This is just a personal suggestion, and I hope to see a better approach.

MMZK1526 commented 12 hours ago

catch is just like default, it'll always return valid parse. Allowing the catch to rethrow would change its semantics, and I’m not sure if the author would be willing to make such a change. For now, I suggest wrapping a utility method to achieve the same effect.

function addCatchInDev(schema: z.ZodType<any>, wrapper: () => any) {
  if (env === "dev") {
    return schema.catch(wrapper);
  }

  return schema;
}

const schema = addCatchInDev(z.string(), () => defaultValue);

This is just a personal suggestion, and I hope to see a better approach.

Thank you for the suggestion, I can do it this way for now 🙏🏼

Perhaps instead of changing catch, there can be another method such as handle that provides this more versatile error-handling mechanism?

sunnylost commented 12 hours ago

In fact, I really hope that superRefine can become more powerful, so that both the normal flow and exceptions can be handled within the callback function.