reactjs - 使用表单验证器 ZOD 的 discriminatedUnion() 函数来区分三种表单
ValidationSchema = z.object({
AuthenticationBlock: z.object({
ChoiceOfForm: z.enum()
DataBlock: z.discriminatedUnion(ChoiceOfForm, [
z.object({ ChoiceOfForm = 1, empty fields}) //corresponds to the basic form
z.object({ ChoiceOfForm = 2, just username/pw fields) //corresponds to less basic form
z.object({ ChoiceOfForm = 3, user/pw + many fields}) //corresponds to advanced form
])
})
})
对象示例:
export type AuthenticationFormValues = {
AuthenticationBlock?: {
choice?: AuthenticationFormChoice | undefined;
data: {
password?: string;
username?: string;
formAuthenticationConfig?: {
formUrl?: string;
javaScriptLoadingDelayInMilliseconds?: number;
forceLogin?: boolean;
customLoginSequence?: string;
authenticationFailed?: FormAuthenticationFailedConfiguration;
};
};
};
};
choiceOfForm 是一个 ENUM,对应三个单选按钮,它们会展开不同的表单(1、2 或 3)。我想使用 ZOD 的 discriminatedUnion() 函数,根据选择的 choiceOfForm(1、2 或 3)启用正确的表单验证块。有没有办法将 choiceOfForm 变量传递给 discriminatedUnion(choiceOfForm, ...) 来实现这个功能?
谢谢
答案#1
我认为你可以通过类似这样的东西来实现你想要的效果:
import { z } from "zod";
enum ChoiceOfForm {
Option1 = 1,
Option2 = 2,
Option3 = 3
}
// Defining this once since it's shared between two of the arms.
const PasswordFields = z.object({
password: z.string(),
email: z.string().email()
});
const schema = z.discriminatedUnion("choice", [
z.object({
choice: z.literal(undefined),
}),
z.object({
choice: z.literal(ChoiceOfForm.Option1)
}),
z.object({
choice: z.literal(ChoiceOfForm.Option2)
}).merge(PasswordFields),
z.object({
choice: z.literal(ChoiceOfForm.Option3),
extraOption: z.number()
}).merge(PasswordFields)
]);
Zod 的 discriminatedUnion 函数将你将要用于区分的键作为第一个参数,以及联合的每个“分支”的模式列表。请注意,由于 z.literal(undefined) 选项,几乎任何对象都可以使用该模式成功解析。你可能想要省略这种可能性,但我不确定你的业务需求。
如果你成功使用这个模式解析某些内容,你可以使用 switch 或 if 语句检查 choice 的值,并像处理普通判别联合一样缩小类型。
