zod: set min max after transform string to number

Viewed 1958

I have number or numeric string, I want transform it to number and continue validate it by .min() .max(), but it don't work as I expected

const numberValid = z.number().or(z.string().regex(/^\d+$/).transform(Number));

const positiveNumber = numberValid.min(0); // method don't exist
1 Answers

The problem is that the transform is going to return a z.ZodEffect which has methods for doing further transformations, but has lost track of the fact that it was originally z.string. The min method from z.number isn't accessible because the outer type is going to be z.ZodUnion which also doesn't know about the min refinement.

I think to get the behavior you're looking for something like this might be the approach I would take:

const thing = z
  .number()
  .or(z.string().regex(/\d+/).transform(Number))
  .refine((n) => n >= 0);

Which is admittedly a little lack luster because we can't rely on min with its simplified syntax and nicer errors. You could solve the latter problem by adding a { message: 'value was less than 0' } as the second argument to refine.

Related