资讯动态

TIL 项目实战:理解 Yup Schema 的异步校验机制,用 Promise 正确编写表单校验

发布时间:2026/10/6 12:23:41 来源:尧图企业网站定制
文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载Yup 提供了一套灵活的对象 Schema 校验 DSL而理解校验本身是异步的是正确使用它的关键前提。本篇以本仓库TIL 项目的 javascript/yup-schemas-are-validated-asynchronously.md 为骨架结合仓库内其余 Yup 相关笔记讲清validate()返回 Promise 的行为、then/catch的用法以及它在 Formik 表单场景中的实际配合方式。读完后你将掌握如何定义最小 Schema、如何用 Promise 链或async/await消费校验结果、如何读取校验错误数组以及如何联动typeError()、ref()等进阶能力。一、Yup 的核心模型Schema 即校验 DSLYup 的核心思想是先描述数据的形状与约束再用它去校验任意输入值。仓库笔记 javascript/yup-schemas-are-validated-asynchronously.md 开篇即给出了最简示例如果希望强制某个值必须是数字只需用内置的类型构造器定义一个 Schemaconst numSchema yup.number();这一行代码的背后是一整套可链式调用的 DSL除了number()Yup 还提供了string()、boolean()、date()、object()、array()等类型构造器以及required()、min()、max()、oneOf()、typeError()等约束与错误定制方法。仓库中 javascript/check-the-password-confirmation-with-yup.md 展示了如何用Yup.object()把多个字段的约束组合成一个完整对象 Schemaimport * as Yup from yup; validationSchema: Yup.object({ password: Yup.string().required(Password is required), passwordConfirmation: Yup.string() .oneOf([Yup.ref(password), null], Passwords must match) });这里ref(password)让passwordConfirmation的校验能跳出自身去引用同 Schema 中的password值oneOf的第二个参数则是校验失败时展示的自定义提示文案。它印证了 Yup 的 DSL 是声明式的约束写在 Schema 上执行与报错全部由库负责。二、校验是异步的validate() 返回 Promise这是本文最核心、也最容易踩坑的一点Yup 的校验是异步的。validate()方法返回的是一个 Promise而不是同步的真/假值。仓库原文演示了标准消费方式const validator (val) { numSchema.validate(val) .then(result { console.log(result); // 校验通过时result 就是 val 本身 return true; }) .catch(error { console.log(error.errors); // 校验失败时error.errors 是错误消息数组 return false; }); };行为与结果一目了然校验通过Promise resolve进入then分支result是被校验通过的值通常即输入值val因为number()Schema 会把合法值原样返回校验失败Promise reject进入catch分支error.errors是一个字符串数组包含一条或多条校验错误消息。因此调用者绝不能用同步的返回值判断通过/失败而必须等待异步结果validator(5) // true validator(what) // false正因为validate()是异步 API它的返回值天然可以接续 Promise 链——例如先校验、再携带校验通过后的结果继续做下一步操作。仓库 javascript/resolve-and-pass-multiple-values-from-a-then.md 对 Promise 链中间传值做了补充当后续then需要同时拿到多个异步结果时可以用Promise.all一并解析并透传fetchTrainer(trainerName) .then(response { const trainerData response.body; return Promise.all([ trainerData, fetchPokemonFor({ trainerId: trainerData.id }) ]); }) .then(([trainerData, pokemonResponse]) { // 同时拿到两个结果 });同理如果表单里有多个 Schema 需要并发校验也可以把多个schema.validate(...)组成的 Promise 数组交给Promise.all让校验并行执行、一次性拿到所有结果。三、用 async/await 改写更贴近直觉的校验代码既然validate()返回 Promise那么在现代 JavaScript 里完全可以用async/await写出可读性更高的等价逻辑。原始笔记中的then/catch版本可以改写成const validator async (val) { try { const result await numSchema.validate(val); console.log(result); // 校验通过result 即 val return true; } catch (error) { console.log(error.errors); // 校验失败错误消息数组 return false; } };两种写法行为完全一致await之后的代码对应thencatch块对应catch。实际项目里更常见的做法是把校验与业务处理分离——校验通过后再做后续操作async function handleSubmit(value) { const validated await numSchema.validate(value); // 失败会抛出被上层捕获 // 走到这里说明校验已通过validated 即为安全值 return doSomething(validated); }需要留意的是在async函数中如果不在本函数内try/catchreject 的 Promise 会向上抛出务必在调用链的更高层统一捕获否则可能产生未处理的 Promise 拒绝unhandled rejection。四、失败分支的深入error.errors 与自定义错误消息catch分支拿到的error对象里errors数组是最常用的字段。它的组成取决于 Schema 上的约束以及是否启用了遇到第一个错误即中止。在此基础上仓库笔记 javascript/custom-type-checking-error-messages-with-yup.md 指出默认的类型错误消息冗长且不适合直接展示给用户。例如用yup.number()校验hey默认报错大致为this must be anumbertype, but the final value was:NaN(cast from the valuehey).这条消息把内部类型转换细节NaN、cast暴露给了最终用户观感不佳。解决办法是用typeError()重新定义类型检查阶段的错误文案const numSchema yup.number().typeError(Invalid number);此时校验非法输入时error.errors里就会是Invalid number这条自定义消息。这个例子说明异步校验的错误分支同样可以被精细定制errors数组里到底是默认消息还是自定义文案取决于 Schema 的配置。五、与表单框架配合Formik 中的异步校验落地理解了校验是异步的就能解释为什么以 Yup 为校验后端的表单库如 Formik要把校验设计成提交后异步等待结果。仓库 react/formiks-validation-schema-as-a-function.md 展示了 Formik 通过validationSchema接收 Yup Schema 的标准姿势const MyComponent withFormik({ validationSchema: yup.object().shape({ email: yup.string().required(), feedback: yup.string().required(), }), })(MyForm);更进一步validationSchema还可以是一个函数其第一个参数是组件收到的props从而按条件动态构造校验规则validationSchema: (props) { let emailSchema; if (props.allowAnonymous) { emailSchema yup.string(); } else { emailSchema yup.string().required(); } return yup.object().shape({ email: emailSchema, feedback: yup.string().required(), }); }Formik 内部会调用schema.validate(...)并对返回的 Promise 做 await只有校验 resolve 之后表单才进入可提交状态reject 时则把error.errors映射到各字段的错误信息上。这也解释了本文的核心结论只要底层 Schema 校验是异步的任何接入方手写代码、Formik、REST 层都必须以异步方式等待其结果react/formik-connected-components.md 中通过connect()读取的formik.errors等状态本质上都是这一异步流程产出的结果。六、小结把异步刻进 Yup 的使用习惯围绕 javascript/yup-schemas-are-validated-asynchronously.md可以提炼出三条可直接迁移到项目中的结论定义即声明yup.number()一行即构成可复用的校验 Schema配合object()、ref()、typeError()等能力可组合出复杂的对象校验参见 密码确认校验 与 自定义类型错误消息消费即异步validate()永远返回 Promise成功走then/await之后失败走catch错误详情在error.errors数组中多条校验可借助Promise.all并发执行接入需等待无论手写校验函数还是交给 Formik 的validationSchema都必须把校验当作异步操作来编排这正是 Yup 这一类基于 Promise 的 Schema 校验库的核心心智模型。赞分享文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载相关推荐rsuite 集成 React Hook Form 与 Yup用 yupResolver 实现 Schema 级表单校验rsuite 集成 React Hook Form 与 Yup用 yupResolver 实现 Schema 级表单校验 React Suitersuite前端UI组件React Suite 与 Formik Yup 集成指南用 Yup Schema 构建声明式表单校验React Suite 与 Formik Yup 集成指南用 Yup Schema 构建声明式表单校验 导读 本文基于 React Suite 官方文档中前端UI组件TanStack Form Solid 表单验证完全指南时机控制、字段级与表单级校验、异步校验与 Standard Schema 集成TanStack Form Solid 表单验证完全指南时机控制、字段级与表单级校验、异步校验与 Standard Schema 集成 表单验证是 TanSt前端UI组件上一篇oh-my-opencode-slim 后台任务会话管理Task Session Manager深度解析多 Agent 协作下的作业看板、别名复用与生命周期编排下一篇ThinkPad风扇控制终极指南如何用TPFanCtrl2实现静音与性能的完美平衡创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑