form icon indicating copy to clipboard operation
form copied to clipboard

zod-form-adapter turns all errors into one comma separated string, meta.errors assumes an array

Open Pascalmh opened this issue 1 year ago • 1 comments

Describe the bug

At the moment the zod-form-adapter's zodValidator validate and validateAsync functions turn the errors that zod reports into a comma separated string:

return result.error.issues.map((issue) => issue.message).join(', ')

When we want to display the Error(s) to the User the field.state.meta.errors field returns an array ValidationError[] which now only has one entry (the comma separated string.

Your minimal, reproducible example

https://stackblitz.com/edit/tanstack-form-r8vroz?file=src%2Findex.tsx

Steps to reproduce

  1. Open the Stackblitz
  2. The Form is already in the Error state (the Input # does not match the min-length nor the regex (letters a-Z)
  3. Observe: both Error messages are separated by a comma and a space => should only be a comma, see FieldInfo-Function
  4. You can also check the Console (you can filter for the string "errors")

Expected behavior

As a User I expect field.state.meta.errors to be an array (type: ValidationError[]) with a length that matches the number of errors that resulted from the zod schema validation

BUT I'm seeing an array (type: ValidationError[]) with the length of 1 no matter how many validation errors occurred.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

Not platform related

TanStack Form adapter

react-form

TanStack Form version

0.32.0

TypeScript version

No response

Additional context

No response

Pascalmh avatar Sep 06 '24 07:09 Pascalmh

I think there is a bug in the definition of the ValidationError type

It is currently defined as:

export type ValidationError = undefined | false | null | string

Searching through the codebase there are places where ValidationError | undefined is specified:

const validatesPromises: Promise<ValidationError | undefined>[] = []
const linkedPromises: Promise<ValidationError | undefined>[] = []

This doesn't make sense as ValidationError already includes undefined in the union type.

Then there's this:

/**
   * An array of errors related to the field value.
   */
errors: ValidationError[]

where errors is an array of ValidationError - where the items of the array could be of type undefined | false | null | string so working with the errors requires an additional falsy check.

How to fix it?

My guess is that the ValidationError should be Array<string> | undefined | false | null

Related Issues

  • This discussion seams related as well: https://github.com/TanStack/form/discussions/946

Pascalmh avatar Sep 11 '24 09:09 Pascalmh

I have the same issue and wonder why this issue is not commented/flagged yet. Is this a bug or a feature? Personally, I would prefer not having the errors be joined and would therefore export an array with the custom transformErrors option.

mimamuh avatar Dec 07 '24 10:12 mimamuh

I have the same issue too.

adhithiya05 avatar Dec 17 '24 17:12 adhithiya05

@adhithiya05 You can work around this by using the transformErrors option of the zodValidator like so; sadly it doesn't allow returning an array currently:

validatorAdapter: zodValidator({
    transformErrors: (errors) => {
        return errors.map(error => error.message).join('#!#'); 
    }
}),

And somewhere in your form / component you simply split the error again:

errors[0].split('#!#');

mimamuh avatar Dec 17 '24 20:12 mimamuh

The meta.errors array contains the errors from all validators, that's why if you only have the onChange set you'll either find an empty array or an array with one element. It is working as expected and there's no bug to fix there.

Allowing to return an array of errors from a single validator might be a completely different topic, I wrote down some notes in the discussion at #946

Balastrong avatar Dec 17 '24 21:12 Balastrong