类型级 DSL 中的错误消息
向 DSL 用户展示有帮助的编译错误。
类型级 DSL 中的错误消息 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。
类型级 DSL 中的易读错误
类型级 DSL 最困难的部分,是让失败信息易于理解。原始的 never 或“不可赋值”错误会让用户困惑。我们通过品牌化错误类型和精心设计的 never 消息,提供描述性错误。
never 类型的问题
当验证失败并解析为 never 时,编译器会说“类型 X 的参数无法赋给 never”,却不会告诉用户原因。我们可以做得更好。
品牌化错误类型
不要返回普通的 never,而应返回一种形状独特的错误类型,并在其类型中携带人类可读的消息字符串。
type TypeError<Msg extends string> = {
readonly __error: Msg;
};
type E = TypeError<"Column 'foo' does not exist">;从验证中返回错误
验证器会返回有效值类型,或返回描述问题的品牌化错误。“包含点号”的检查是一个模板字面量模式(实际代码中使用反引号);这里将其记作 HasDot。
// HasDot<S> is the backtick pattern: any text, ".", any text.
type Validate<S extends string> =
S extends HasDot
? S
: TypeError<"Path must contain a dot, e.g. user.name">;强制显示错误
请约束参数,使传入的任何内容都不能赋给错误品牌类型,从而显示该消息。错误类型会直接出现在编译器输出中。
declare function path<S extends string>(
p: Validate<S> extends TypeError<infer M> ? TypeError<M> : S
): void;
path("oops");
// Error message includes: __error: "Path must contain a dot..."区分多个错误
不同的失败会返回不同的消息,因此用户可以获得具体指导,而不是面对一种通用拒绝。HasDot 仍然是表示“包含点号”的反引号模板字面量模式。
type Check<S extends string> =
S extends "" ? TypeError<"Path cannot be empty">
: S extends HasDot ? S
: TypeError<"Missing dot separator">;never 类型的巧妙用法
另一种技术是将值位置与字面量消息配对,以便悬停查看时显示该消息。您可以将出错类型与带标签的对象进行交集组合。
type Invalid<M extends string> = { error: M } & never;
// using never keeps it unassignable while the label hints the cause流式 DSL 中的错误
在链式 DSL 中,请让无效的下一步返回品牌化错误类型,而不是有效阶段,这样编辑器就会在错误发生的位置显示消息。
interface Stage {
// calling done() before where() yields a labeled error
done(): TypeError<"Call .where() before .done()">;
}保持消息简短
过长的消息类型会使编译器输出膨胀,并拖慢工具运行。请优先使用简洁且可执行的短语。如果代价很低,可以包含出错的令牌,但请避免巨大的插值内容。
测试错误
请编写类型级测试,断言已知错误输入会出现错误品牌,这样重构就不会在不知不觉中损害开发者体验。
type Expect<T extends true> = T;
type _t = Expect<Validate<"oops"> extends TypeError<any> ? true : false>;为何重要
DSL 的质量取决于其错误信息。品牌化错误类型可以将晦涩的 never 失败转化为自解释的消息,从而显著改善使用类型级接口时的体验。
快速检查
请确认您对类型级错误消息的理解。
回顾
为了让类型级 DSL 易于使用,请用包含易读消息的品牌化错误类型替代单独的 never。验证器会返回有效类型或特定的错误品牌;约束参数可以让消息显示在编译器输出中。请保持消息简短,并对其进行测试。
常见问题解答
「类型级 DSL 中的错误消息」课时是免费的吗?
是的 — 「类型级 DSL 中的错误消息」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。
「类型级 DSL 中的错误消息」这节课中我会学到什么?
向 DSL 用户展示有帮助的编译错误。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 TypeScript Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「类型级 DSL 中的错误消息」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 TypeScript Academy 课中编写并运行代码吗?
能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 什么是类型级 DSL
- 设计流式查询 DSL
- 编译时输入验证
- 类型级 DSL 中的错误消息