如何使用Yup实现数组的条件验证?
用Yup实现基于状态的数组条件验证
我正尝试使用Yup实现数组的条件验证,但遇到了困难。表单定义如下:
enum Status { RED = 'Red', GREEN = 'Green', YELLOW = 'Yellow', } interface MyField { fieldType: MyFieldType; fieldValue: string; } enum MyFieldType { FIELD_TYPE_1 = '1', FIELD_TYPE_2 = '2', FIELD_TYPE_3 = '3', } const validationSchema = yup.object({ status: yup.mixed<Status>().required(), fields: yup.array().of(yup.mixed<MyField>()).required() });
需求是fields数组要根据status字段的值进行条件验证,需包含特定fieldType的元素:
- 当
status === Status.RED时,数组必须包含一个fieldType为MyFieldType.FIELD_TYPE_1的元素,且该元素的fieldValue不能为空 - 当
status === Status.GREEN时,数组必须同时包含fieldType为MyFieldType.FIELD_TYPE_2和MyFieldType.FIELD_TYPE_3的元素,且这两个元素的fieldValue都不能为空 - 其他状态可自定义组合规则
我知道Yup的when方法,但不确定如何针对该场景正确使用,目前的框架如下:
fields: yup.array().of(yup.mixed<MyField>()).when('status', { is: (status: Status) => status === Status.GREEN, then: yup.array().of(// 不知道如何验证数组包含指定MyFieldType且对应fieldValue非空 ) }
完整实现方案
要实现这种数组的条件验证,结合Yup的when方法、test自定义验证以及数组约束规则即可完成。以下是完整的验证Schema:
import * as yup from 'yup'; // 定义单个MyField的通用验证规则 const myFieldSchema = yup.object<MyField>().shape({ fieldType: yup.mixed<MyFieldType>().oneOf(Object.values(MyFieldType)).required(), fieldValue: yup.string().trim().required() }); const validationSchema = yup.object({ status: yup.mixed<Status>().oneOf(Object.values(Status)).required(), fields: yup.array().of(myFieldSchema).required() // RED状态下的验证规则 .when('status', { is: Status.RED, then: schema => schema.test( 'has-valid-field-type-1', '必须包含fieldType为1的字段且值不为空', (fields) => { return fields.some(field => field.fieldType === MyFieldType.FIELD_TYPE_1 && yup.string().trim().required().isValidSync(field.fieldValue) ); } ) }) // GREEN状态下的验证规则 .when('status', { is: Status.GREEN, then: schema => schema.test( 'has-valid-field-type-2-and-3', '必须同时包含fieldType为2和3的字段且值不为空', (fields) => { const hasValidType2 = fields.some(field => field.fieldType === MyFieldType.FIELD_TYPE_2 && yup.string().trim().required().isValidSync(field.fieldValue) ); const hasValidType3 = fields.some(field => field.fieldType === MyFieldType.FIELD_TYPE_3 && yup.string().trim().required().isValidSync(field.fieldValue) ); return hasValidType2 && hasValidType3; } ) }) // YELLOW状态下的自定义规则(示例) .when('status', { is: Status.YELLOW, then: schema => schema.test( 'yellow-status-rule', 'YELLOW状态下的自定义验证提示', (fields) => { // 替换为实际需要的验证逻辑 return fields.length >= 1; } ) }) });
关键逻辑说明
- 单个字段校验复用:先定义
myFieldSchema统一验证数组中每个元素的合法性,确保fieldType是枚举有效值,fieldValue是非空字符串,避免重复编写校验逻辑。 - 链式
when调用:针对不同的status值,链式调用when方法添加对应的数组级校验规则,互不干扰。 - 自定义
test校验:通过test方法编写数组的全局校验逻辑,使用some方法检查数组中是否存在符合要求的元素,同时复用Yup内置的字符串验证确保fieldValue有效。 - 错误提示自定义:每个
test的第二个参数是自定义错误文案,让用户能清晰理解错误原因。
可选优化:复用校验逻辑
如果多个状态需要重复“检查数组包含指定fieldType且值有效”的逻辑,可以抽成工具函数:
const hasValidTargetField = (fields: MyField[], targetType: MyFieldType) => { return fields.some(field => field.fieldType === targetType && yup.string().trim().required().isValidSync(field.fieldValue) ); }; // 调用示例: // return hasValidTargetField(fields, MyFieldType.FIELD_TYPE_1); // return hasValidTargetField(fields, MyFieldType.FIELD_TYPE_2) && hasValidTargetField(fields, MyFieldType.FIELD_TYPE_3);
内容的提问来源于stack exchange,提问作者Franjo Pintarić
相关产品推荐
相关产品推荐

