总结 zod 验证以供重用

Ash*_*ury 7 typescript zod

我正在制作与我同事类似的表格,但有一些额外的字段。我已经获取了他的 zodObject 并用额外的字段扩展了它。

他使用了一堆 .refine 调用来验证他的表单,但我想包装该逻辑并在我的表单上使用它。

提取该逻辑以便我们双方都可以使用的最佳方法是什么?

例如,对车辆进行验证并扩展汽车对象:

export const vehicleZodObject = z.object({
  name: z.string(),
  engine: type: z.enum(['electric', 'combustion']),
})


export const carZodObject = vehicleObject.extend({
  wheels: z.number().min(4),
})
Run Code Online (Sandbox Code Playgroud)

他有很多refine调用链接到他的车辆对象,如下所示:

 .refine((data) => isUnique(data.name), {
      message: 'Characters must be unique',
    })
Run Code Online (Sandbox Code Playgroud)

我需要能够捆绑这些精炼链并在两个 zod 对象上使用它们。

Sou*_*man 8

确切地说最好的方法是什么有点困难,因为我认为有几种选择。

首先,我建议尽可能将改进保留在其适用的领域。例如,refine我不会调用整个对象,而是调用refineforz.string()字段name

export const vehicleZodObject = z.object({
  name: z.string().refine(isUnique, { message: 'Characters must be unique' },
  engine: type: z.enum(['electric', 'combustion']),
});
Run Code Online (Sandbox Code Playgroud)

接下来,可以定义一个辅助函数,对其所传递的模式进行细化。您可以使用两个模式共享的接口进行设置,然后调用所refine提交的模式上的函数:

import { z } from "zod";

interface IShared {
  a: string;
  b: string;
}

function attachRefinements<O extends IShared, T extends z.ZodTypeDef, I>(
  schema: z.ZodType<O, T, I>
) {
  return schema.refine((shared) => shared.a !== shared.b, {
    message: "a and b must be unique"
  });
}

const schema1 = attachRefinements(
  z.object({
    custom: z.boolean(),
    a: z.string(),
    b: z.string()
  })
);

const schema2 = attachRefinements(
  z.object({
    a: z.string(),
    b: z.string(),
    special: z.number()
  })
);
Run Code Online (Sandbox Code Playgroud)

即使在这种情况下,我建议创建一个base仅包含字段a和 的模式b,仅将细化添加到base模式中,然后构建schema1schema2使用z.intersection. 这符合细化尽可能靠近其应用的地方的原则。

const base = z.object({
  a: z.string(),
  b: z.string(),
}).refine((x) => x.a !== x.b, {
  message: 'a and b must be unique',
});

const schema1 = z.intersection(base, z.object({
  custom: z.boolean(),
});
const schema2 = z.intersection(base, z.object({
  special: z.number()
});
Run Code Online (Sandbox Code Playgroud)