valibot: Getting concrete errors in unions is too hard
Hello, first of all, thank you for the work you are putting into this library. Currently I am trying to use it to validate an array of objects that can be of a variety of shapes, hence I use union to specify all the possible types.
When I get an error in a “first level” I get a quite readable message using my very basic “flatten function”. Something like: field name should not be empty at 4.name
However, when the error happens at a nested property, despite I am specifying proper specific errors for everything I get a very generic message: Invalid type at 4.input
I think the cause is the usage of union. Here is a basic example:
function nonEmptyString(name: string) {
return string(`${name} should be a string`, [toTrimmed(), minLength(1, `${name} should not be empty`)])
}
const BasicInputSchema = object({ type: FieldTypeSchema });
const MultiSelectNotesSchema = object({
type: literal("multiselect"), source: literal("notes"),
folder: nonEmptyString('multi select source folder') // can't reach this message
});
const MultiSelectFixedSchema = object({ type: literal("multiselect"), source: literal("fixed"), multi_select_options: array(string()) });
export const MultiselectSchema = union([MultiSelectNotesSchema, MultiSelectFixedSchema]);
const InputSelectFixedSchema = object({
type: literal("select"),
source: literal("fixed"),
options: array(object({
value: nonEmptyString('Value of a select option'), // can't reach this message
label: string()
}))
});
const InputTypeSchema = union([
BasicInputSchema,
MultiselectSchema,
InputSelectFixedSchema
]);
const FieldDefinitionSchema = object({
name: nonEmptyString('field name'), // This is fine
label: optional(string()),
description: string(),
input: InputTypeSchema
});
const FieldListSchema = array(FieldDefinitionSchema);
export function validateFields(fields: unknown) {
const result = safeParse(FieldListSchema, fields);
if (result.success) {
return []
}
console.error('Fields issues', result.issues)
return result.issues.map(issue =>
`${issue.message} at ${issue.path?.map(item => item.key).join('.')}`
);
}
I will be very grateful if you either provide a nicer way to reach this errors or a workaround to implement it myself.
Cheers
About this issue
- Original URL
- State: closed
- Created 8 months ago
- Comments: 18 (8 by maintainers)
Commits related to this issue
- Add discriminatedUnion schema #90 #216 — committed to fabian-hiller/valibot by fabian-hiller 8 months ago
I have implemented
discriminatedUnion
. The API is expected to be available in the next release in a few days.Yes, I see your point, and makes complete sense, I was thinking only in my particular use-case. What I think is needed in this case, it is a different combinator. Union, as you pointed out, can end having contradictory types, a tagged-union however should uniquely point you to one specific type through it’s tag. So my proposal is you add a new method, called however you want (io-ts calls it sum) where you define your tag key then you can just show the error of the type whose tag matches or just the sum error in case none matches:
v0.20.0 is now available
Awesome, thanks for the update!
On Mon, Oct 23, 2023 at 9:49 PM Fabian Hiller @.***> wrote:
–
https://danielorodriguez.com
The reason I suspect the problem is using the union type is because
issue.issues
array that I don’t understand: