robertLichtnow / zod-formik-adapter

An adapter for zod object validation to Formik validation schema
https://www.npmjs.com/package/zod-formik-adapter
MIT License
159 stars 15 forks source link

[BUG] `toFormikValidationSchema` gives "Required" error for empty string (`""`) when validating for `z.string()` #28

Open Inambe opened 2 months ago

Inambe commented 2 months ago

Describe the bug It's a bit weird to explain but when using toFormikValidationSchema, empty string resolves to "Required" error (that's the opposite of how Zod works).

To Reproduce Steps to reproduce the behavior:

  1. Create this simple form:
    <Formik
    initialValues={{ name: "" }}
    validationSchema={toFormikValidationSchema(
    z.object({
      name: z.string(),
    })
    )}
    >
    {({ handleSubmit, errors, values, handleChange }) => (
    <form onSubmit={handleSubmit}>
      {console.log(errors)}
      <input
        value={values.name}
        id="name"
        onChange={handleChange}
      />
    </form>
    )}
    </Formik>
  2. Check the console (there won't be any error)
  3. type something and then remove it
  4. You'll see the "Required" error in the console

Expected behavior Strangely, toFormikValidate works perfectly fine. If you take example above and change toFormikValidationSchema to toFormikValidate and validationSchema to validate, you won't see that error (that's the correct behavior according to Zod. An empty string is a valid string).

Screenshots NA

Desktop (please complete the following information):

Node version: v18.20.3

Zod, Formik and zod-formik-adapter versions:

Additional context NA

bogdanS-e commented 2 months ago

Same for me. I didn't find the solution yet name: z.string().min(1, 'Some error')

but in formik.errors I see name: "Required" and not my custom error

jesseokeya commented 1 month ago

Having similar issue

jesseokeya commented 4 weeks ago

Looks like this project is no longer maintained. You can create a fork of this and fix with the code below.

export class ValidationError extends Error {
  public name = 'ValidationError';

  public inner: Array<{ path: string; message: string }> = [];

  public constructor(message: string) {
    super(message);
  }
}

const transformErrorMessage = (e: ZodIssue): string => {
  const { message, path } = e;

  const prefix = path.map((part) => (typeof part === 'number' ? `[${part}]` : part)).join('.');
  return `${prefix} is ${message.toLowerCase()}`;
};

function createValidationError(e: ZodError): ValidationError {
  const error = new ValidationError(e.message);

  error.inner = e.errors.map((err) => ({
    message: transformErrorMessage(err),
    path: err.path.join('.'),
  }));

  return error;
}

/**
 * Wrap your zod schema in this function when providing it to Formik's validation schema prop
 * @param schema The zod schema
 * @returns An object containing the `validate` method expected by Formik
 */
export function toFormikValidationSchema<T>(
  schema: ZodSchema<T>,
  params?: Partial<ParseParams>,
): { validate: (obj: T) => Promise<void> } {
  return {
    async validate(obj: T) {
      try {
        await schema.parseAsync(obj, params);
      } catch (err: unknown) {
        throw createValidationError(err as ZodError<T>);
      }
    },
  };
}