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

如何为TypeScript联合类型User构建Yup验证Schema?

解决Yup联合类型Schema的TypeScript类型匹配问题

问题原因

你当前的Schema定义中,privileges字段被声明为可选字符串,但你的User联合类型要求:

  • 当authenticationType为basicUser时,privileges是必填字符串
  • 当authenticationType为adminUser时,privileges字段不存在

这种结构差异导致TypeScript无法将你的ObjectSchema与User类型对齐,即使运行时验证正常,类型检查也会失败。

可行解决方案:使用yup.lazy动态匹配分支Schema

通过yup.lazy根据authenticationType的值动态选择对应的子Schema,完美匹配联合类型的结构:

步骤1:定义各分支的独立Schema

先分别为BasicUser和AdminUser创建精确匹配的Schema:

import * as yup from 'yup';
import { AuthenticationType, User, BasicUser, AdminUser } from './types';

// 定义BasicUser的Schema
const basicUserSchema = yup.object<BasicUser>().shape({
  name: yup.string().required(),
  authenticationType: yup.string().oneOf(['basicUser']).defined().required(),
  privileges: yup.string().required()
});

// 定义AdminUser的Schema
const adminUserSchema = yup.object<AdminUser>().shape({
  name: yup.string().required(),
  authenticationType: yup.string().oneOf(['adminUser']).defined().required()
});

步骤2:用yup.lazy组合成联合Schema

使用lazy根据输入值的authenticationType动态选择对应的Schema,同时指定类型为yup.Schema<User>:

const userSchema: yup.Schema<User> = yup.lazy((value) => {
  switch (value?.authenticationType) {
    case 'basicUser':
      return basicUserSchema;
    case 'adminUser':
      return adminUserSchema;
    default:
      // 默认返回一个会验证失败的Schema,处理未知类型
      return yup.object().test('invalid-type', 'Invalid user type', () => false);
  }
});

验证测试

现在可以正常验证你的示例数据,同时TypeScript类型检查完全通过:

// 验证AdminUser
userSchema.validate(bobAdmin)
  .then(validUser => console.log(validUser)) // 正常通过
  .catch(err => console.error(err));

// 验证BasicUser
userSchema.validate(sallyBasicUser)
  .then(validUser => console.log(validUser)) // 正常通过
  .catch(err => console.error(err));

// 验证缺少privileges的BasicUser会报错
userSchema.validate({ name: 'Test', authenticationType: 'basicUser' })
  .catch(err => console.error(err)); // 提示privileges必填

另一种方案:使用yup.mixed().oneOf()结合Schema数组

如果你偏好oneOf的写法,也可以将两个分支Schema放入oneOf中:

const userSchema: yup.Schema<User> = yup.mixed().oneOf([
  basicUserSchema,
  adminUserSchema
]) as yup.Schema<User>;

注意:这里的类型断言as yup.Schema<User>是必要的,因为Yup的类型推断无法自动识别数组中的Schema对应联合类型。

关键技巧总结

  • 联合类型的Schema需要精确匹配每个分支的结构,不能用单一ObjectSchema覆盖所有情况
  • yup.lazy是处理动态类型最可靠的方式,能根据输入值动态切换验证逻辑
  • 避免在单一ObjectSchema中用when处理联合类型的必填差异,这种方式无法让TypeScript正确推断类型

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:05:03