zod:将字符串转换为数字后设置最小最大

Har*_*ual 6 typescript zod

我有数字或数字字符串,我想将其转换为数字并继续通过 验证它.min() .max(),但它没有按我的预期工作

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

const positiveNumber = numberValid.min(0); // method don't exist
Run Code Online (Sandbox Code Playgroud)

Sim*_*ens 19

从 version 开始,您可以像这样3.20使用:z.coerce.number()

const numberValid = z.coerce.number().min(0)

numberValid.parse(123) // OK
numberValid.parse(-123) // ERROR
numberValid.parse("123") // OK
numberValid.parse("-123") // ERROR
Run Code Online (Sandbox Code Playgroud)


Sou*_*man 16

问题是transform将会返回 a z.ZodEffect,它具有进行进一步转换的方法,但已经忘记了它最初是 的事实z.stringminfrom 的方法不可z.number访问,因为外部类型z.ZodUnion也不知道min细化。

我认为要获得您正在寻找的行为,我可能会采取以下方法:

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

诚然,这有点缺乏光泽,因为我们不能依赖min它简化的语法和更好的错误。{ message: 'value was less than 0' }您可以通过添加 a作为第二个参数来解决后一个问题refine

编辑

这引起了一些关注,我意识到还有另一种方法可以做到这一点。您可以preprocess在将值传递给 之前使用 来处理字符串z.number。如果你这样做,你仍然可以利用.min所有好的错误消息和东西。

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),
)
Run Code Online (Sandbox Code Playgroud)