Reputation: 67248
I have a property that is supposed to allow only certain numbers:
{
...
x: 1 | -1
}
How to define this in the input validation schema?
If input is JSON it's easy:
x: z.union([z.literal(-1), z.literal(1)])
but if input comes in the search query, then values are strings, so I need to be able to coerce to number, but still limit to -1 and 1 to make the inferred type from the schema compatible with the TypeScript type.
Upvotes: 2
Views: 113
Reputation: 3019
One way to do that would be to accept both numbers and strings, transform strings to number then refine the result to parse only allowed numbers:
// union of
z.union([
z.number(), // number or
z.string().transform(str => parseInt(str, 10)) // string transformed to number
]).refine(v => [1,-1].includes(v)); // refined to allow a set of numbers
or alternatively pipe the transformation to your original schema:
// union of
z.union([
z.number(), // number or
z.string().transform(str => parseInt(str, 10)) // string transformed to number
]).pipe(z.union([z.literal(1), z.literal(-1)]))
Or you can use a preprocess also followed by a pipe:
z.preprocess(
v => typeof v === 'number' ? v : parseInt(v, 10), // preprocessing
z.number() // as number
).pipe(z.union([z.literal(1), z.literal(-1)]));
The docs also point to coerce which can work the same way and matches more closely your original question albeit with less control on the conversion:
// coerce internally uses Number(value)
z.coerce.number().pipe(z.union([z.literal(1), z.literal(-1)]));
The resulting type should correctly be inferred as number in all cases and probably as the required union in the pipe cases. Just choose your favorite flavor and control level :)
Upvotes: 1