yup 本身不直接提供“自动剥离无效字段”的内置功能,但可通过捕获校验错误并手动过滤原始数据,安全地保留合法字段、移除校验失败的键值对。
yup 本身不直接提供“自动剥离无效字段”的内置功能,但可通过捕获校验错误并手动过滤原始数据,安全地保留合法字段、移除校验失败的键值对。
在实际表单处理或 API 数据清洗场景中,我们常需要“尽最大努力保留有效数据”,而非因单个字段(如 age: -1)校验失败就整体拒绝整个对象。Yup 的 .validate() 默认在遇到任何错误时抛出异常,返回完整错误列表(含 path 字段),这恰好为按路径精准剔除无效字段提供了可靠依据。
以下是一个健壮、可复用的剥离方案:
import { object, string, number, date, ValidationError } from 'yup';
const userSchema = object({
name: string().required(),
age: number().required().positive().integer(),
email: string().email().optional(),
website: string().url().nullable().optional(),
createdOn: date().default(() => new Date()),
});
// ✅ 安全剥离函数:返回仅含通过校验字段的纯净对象
async function stripInvalid<t>(schema: any, data: unknown): Promise<t> {
try {
// 若全部字段有效,直接返回标准化后的数据(含默认值、类型转换等)
return await schema.validate(data, { abortEarly: false });
} catch (err) {
if (err instanceof ValidationError) {
// 浅拷贝原始数据(注意:仅适用于扁平对象;嵌套需深克隆)
const stripped = { ...data } as Record<string unknown>;
// 遍历所有校验错误,按 path 删除对应字段
err.inner.forEach(({ path }) => {
if (path && Object.prototype.hasOwnProperty.call(stripped, path)) {
delete stripped[path];
}
});
return stripped as T;
}
throw err; // 非校验错误,重新抛出
}
}
// 使用示例
const input = {
name: 'jimmy',
age: -1,
email: 'invalid-email',
website: 'https://example.com',
};
stripInvalid(userSchema, input).then(console.log);
// 输出:{ name: 'jimmy', website: 'https://example.com' }
// ✅ name(有效)、website(有效)被保留;
// ❌ age(-1 不满足 positive)、email(格式错误)被剥离。</string></t></t>
⚠️ 关键注意事项:
- abortEarly: false 必须显式传入 validate() 选项,否则仅返回首个错误,导致其他无效字段无法被识别和剥离;
- 此方案操作的是原始输入对象的浅拷贝,不修改源数据,符合函数式编程原则;
- 对于嵌套对象(如 address.city),path 为字符串路径(如 'address.city'),当前实现仅支持一级键删除;如需深度剥离,建议配合 Lodash 的 unset() 或递归解析 path;
- 剥离后结果不包含 Yup 的默认值或类型转换(如 date().default(...)),因为这些逻辑仅在完整校验成功时生效。若需默认值,应在剥离后对剩余字段单独应用 .cast() 或分步处理。
总结:Yup 的错误结构设计天然适配数据清洗需求。通过 ValidationError.inner 获取精确失效路径,并结合对象操作,即可实现声明式 Schema 驱动的智能字段剥离——既保持验证逻辑集中可控,又赋予数据处理足够的灵活性。











