The issue here is that the transform
method is returning a z.ZodEffect
, which provides further transformation methods, but loses the original type information of z.string
. As a result, the min
method from z.number
is not accessible because the outer type is z.ZodUnion
, which does not recognize the min
refinement.
To achieve the desired behavior, you could consider the following approach:
const thing = z
.number()
.or(z.string().regex(/\d+/).transform(Number))
.refine((n) => n >= 0);
Although this solution may seem somewhat lacking, as it does not allow for using min
with its simplified syntax and clearer error messages, you could address this by providing a custom message like
{ message: 'value was less than 0' }
as the second argument to the
refine
method.
Edit
Upon further consideration, another approach is possible. You can utilize the preprocess
function to preprocess strings before passing them to z.number
. By implementing it this way, you can still make use of .min
with its detailed error messages and other functionalities.
const numberValid2 = z.preprocess(
(input) => {
const processed = z.string().regex(/^\d+$/).transform(Number).safeParse(input);
return processed.success ? processed.data : input;
},
z.number().min(0),
)