effect-smol Schema错误处理详解:验证错误格式化与国际化完整指南
【免费下载链接】effect-smolCore libraries and experimental work for Effect v4项目地址: https://gitcode.com/GitHub_Trending/ef/effect-smol
在effect-smol(Effect v4 核心库)中,Schema 错误处理通过结构化的Issue 错误树完成:解析失败时,错误携带字段路径、期望类型与实际值,并可按需做验证错误格式化与国际化(i18n)定制。本文面向新手,带你快速掌握错误类型、格式化器与自定义提示词三件套。
为什么 Schema 的错误处理值得重视?
当你用 Schema 解析接口参数、表单数据或配置时,验证失败是常态。effect-smol 的Schema模块把失败原因封装成一棵Issue 树,而不是一个笼统的字符串,带来三个好处:
- 精确定位:嵌套字段出问题时,错误自带路径(如
["user"]["age"]) - 可编程处理:可按错误类型分支处理,而不靠正则解析文案
- 可定制展示:格式化器(Formatter)可替换,支持自定义文案与国际化
核心实现位于 SchemaIssue.ts 与 SchemaError.ts。
一分钟认识 Issue 错误树
每个 Issue 节点都有_tag字段标识类型,分为叶子节点与组合节点两类:
| 节点类型 | 含义 | 典型场景 |
|---|---|---|
InvalidType | 类型不匹配 | 期望字符串却收到数字 |
InvalidValue | 值不满足约束 | 字符串长度不足、数值越界 |
MissingKey | 缺少必填字段 | 对象漏传 key |
UnexpectedKey | 出现多余字段 | 严格模式下传了未知属性 |
Forbidden | 禁止的操作 | 同步上下文中执行了异步操作 |
OneOf/AnyOf | 联合类型匹配问题 | 无一匹配 / 多个匹配 |
Filter/Encoding/Pointer/Composite | 组合包装 | 记录过滤失败、转换失败、路径、多错误聚合 |
解析失败时抛出的是SchemaError,其issue字段就是这棵错误树,message属性会自动调用默认格式化器渲染成可读文本:
try { Schema.decodeUnknownSync(Schema.Number)("not a number") } catch (err) { if (Schema.isSchemaError(err)) { console.log(err.message) // Expected number, got "not a number" } }类型定义详见 SchemaIssue.ts。
验证错误格式化:两种开箱即用的格式化器
Issue 树本身是结构化数据,如何变成人读文案由Formatter决定。effect-smol 内置了两个:
1. 默认字符串格式化器(默认输出)
SchemaIssue.makeFormatterDefault()把错误树扁平化为多行文本,每条错误附带字段路径:
Expected string, got 42 at ["username"] Missing key at ["email"]这也是Issue.toString()与SchemaError.message的底层实现,适合日志、CLI 输出。
2. Standard Schema V1 格式化器(跨库兼容)
SchemaIssue.makeFormatterStandardSchemaV1()输出标准化的issues数组,每项包含message和path,方便对接表单库、React Hook Form 等遵循 Standard Schema 规范的生态:
const formatter = SchemaIssue.makeFormatterStandardSchemaV1() formatter(issue) // { issues: [{ message: "Expected string, got 42", path: ["username"] }] }两个格式化器均支持通过leafHook/checkHook回调替换具体片段的渲染逻辑,是定制文案的关键扩展点,源码见 SchemaIssue.ts。底层的值渲染(日期、循环引用、脱敏值等)由通用的 Formatter.ts 提供。
三步为错误信息做国际化(i18n)
effect-smol 没有内置语言包,但其消息机制天然支持国际化——文案是数据,不是硬编码。推荐三步走:
第一步:在 Schema 注解中写入本地化文案
通过annotateKey等注解为字段指定提示词,格式化时会优先使用注解中的message:
const schema = Schema.Struct({ username: Schema.String.pipe( Schema.annotateKey({ description: "The username used to log in", messageMissingKey: "用户名不能为空" // 缺失该字段时的提示 }) ) })注解还支持messageUnexpectedKey(多余字段)等变体,定义见 Schema.ts。
第二步:按语言选择文案源
常见做法是在 Schema 定义层注入当前语言对应的文案:
const messages = locales[lang] // 你的文案表 const UserSchema = makeUserSchema(messages.zh ?? messages.en)第三步:用自定义 Hook 兜底未注解的错误
对没有注解的错误(如类型不匹配),提供自己的leafHook统一翻译默认模板:
const formatter = SchemaIssue.makeFormatterStandardSchemaV1({ leafHook: (issue) => { if (issue._tag === "InvalidType") { return t("schema.invalidType", { expected: "string" }) } return SchemaIssue.defaultLeafHook(issue) // 其余走默认 } })这样,已注解字段用业务文案,未注解字段走翻译模板,即可实现完整的错误信息国际化。
敏感数据提醒
错误信息中默认包含出错的实际值(如got "abc123")。对外展示前请注意脱敏:SchemaIssue内置了redact逻辑,可将实际值替换为Redacted占位,避免密码、令牌等敏感内容进入日志或前端,相关实现见 SchemaIssue.ts。
总结与延伸阅读
| 需求 | 工具 |
|---|---|
| 读取错误路径与原因 | issue树 +_tag模式匹配 |
| 人读多行文本 | makeFormatterDefault() |
| 对接表单/前端生态 | makeFormatterStandardSchemaV1() |
| 国际化文案 | annotateKey注解 + 自定义leafHook |
| 判断是否为 Schema 错误 | Schema.isSchemaError(err) |
更多 Schema 用法可阅读官方指南 SCHEMA.md,Schema 基础示例参考 10_schema-basics.ts,注解定义见 Schema.ts。掌握 Issue 树、格式化器与注解文案三个概念,你就已经能构建出既清晰又可国际化的验证错误处理方案了 🚀
【免费下载链接】effect-smolCore libraries and experimental work for Effect v4项目地址: https://gitcode.com/GitHub_Trending/ef/effect-smol
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考