You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Zod实现邮箱与用户名输入双重验证的问题求助

解决Zod中邮箱/用户名联合验证失效的问题

问题原因

你当前的Zod Union校验逻辑失效,是因为Zod Union按顺序匹配规则,且普通字符串规则的包容性远强于邮箱规则。只要输入满足非空、长度合规的字符串,就会直接匹配第二个分支(用户名规则),不会触发前面的邮箱格式校验。

解决方案

方法一:使用z.disjunctiveUnion(Zod v3.20+)

disjunctiveUnion会检查所有分支,仅当恰好一个分支验证通过时才判定有效,完美解决Union的顺序匹配问题。同时建议给用户名规则添加额外限制(比如禁止包含@),避免和邮箱混淆。

import { z } from "zod";

const authSchema = z.object({
  emailOrUsername: z.disjunctiveUnion([
    // 邮箱分支
    z.string()
      .min(1, 'Email is required')
      .email('Invalid email')
      .max(100)
      .trim(),
    // 用户名分支
    z.string()
      .min(1, 'Username is required')
      .max(100)
      .trim()
      .refine(val => !val.includes('@'), 'Username cannot contain @ symbol'),
  ]),
});

方法二:自定义superRefine校验逻辑

如果需要更灵活的校验逻辑(比如复杂的用户名规则),可以用superRefine手动控制验证流程:

import { z } from "zod";

const authSchema = z.object({
  emailOrUsername: z.string()
    .min(1, 'Input is required')
    .max(100)
    .trim()
    .superRefine((val, ctx) => {
      // 先验证邮箱格式
      const emailCheck = z.string().email().safeParse(val);
      if (emailCheck.success) return;

      // 验证用户名规则
      const usernameCheck = z.string()
        .refine(v => !v.includes('@'), 'Username cannot contain @')
        .safeParse(val);
      
      if (!usernameCheck.success) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: usernameCheck.error.issues[0].message,
        });
      }
    }),
});

说明

  • disjunctiveUnion更简洁,适合常规场景;
  • superRefine适合需要自定义复杂校验逻辑的场景;
  • 添加用户名禁止@的规则是为了避免用户输入类似user@example的字符串被误判为用户名,提升校验准确性。

内容的提问来源于stack exchange,提问作者Girbi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 15:13:27