0Pricing
TypeScript Academy · 课时

编译时输入验证

在运行时之前拒绝格式错误的 DSL 表达式。

编译时输入验证 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。

编译时输入验证

类型层面的 DSL 可以在运行时之前拒绝格式错误的表达式。使用模板字面量类型和条件类型,我们可以在类型层面验证字符串的结构,并拒绝无效输入。

示例:小型选择器语言

假设我们接受类似"user.name"或"order.items.length"这样的字符串。我们希望在编译时拒绝"user."或".name"。

使用模板字面量进行解析

模板字面量类型使用infer将字符串拆分为多个部分,这是编译时解析的基础。实际模式由反引号分隔(使用推断的头部、点和尾部);我们将这个拆分匹配器记为 DotSplit。

// Real TS: backtick pattern matching Head, ".", Tail.

type Split<S extends string> =
  S extends DotSplit<infer Head, infer Tail>
    ? [Head, ...Split<Tail>]
    : [S];

type P = Split<"a.b.c">; // ["a", "b", "c"]

验证每个片段

条件类型会检查是否存在空片段。空片段表示输入无效。同一个 DotSplit 模式(实际代码中的反引号模板字面量)会驱动递归过程。

type NonEmpty<S extends string> = S extends "" ? false : true;

type Valid<S extends string> =
  S extends DotSplit<infer H, infer T>
    ? H extends "" ? false : Valid<T>
    : NonEmpty<S>;

type V1 = Valid<"a.b">;  // true
type V2 = Valid<"a.">;   // false

以有效性约束接口

请使用有效性类型约束函数参数:有效字符串保留其类型;无效字符串会解析为 never,因此调用无法通过编译。

declare function path<S extends string>(
  p: Valid<S> extends true ? S : never
): void;

path("user.name"); // ok
path("user.");     // Error: argument is never

拒绝未知令牌

您还可以限制允许使用的字符。请仅匹配已知的分段模式;其他任何内容都会归约为拒绝类型。

type Allowed = "user" | "order" | "name" | "items";
type CheckSeg<S extends string> = S extends Allowed ? true : false;

验证操作符

对于类似 "age > 18" 的表达式 DSL,请使用模板字面量匹配操作符,并确保它属于允许集合。匹配器(左空格 O 空格右)在实际代码中是反引号模板字面量;这里将其记作 CondMatch。

type Op = ">" | "<" | "=" | ">=" | "<=";

// Real TS: backtick pattern -> left, " ", infer O, " ", right.
type IsCond<S extends string> =
  S extends CondMatch<infer O>
    ? O extends Op ? true : false
    : false;

type C1 = IsCond<"age > 18">; // true
type C2 = IsCond<"age ! 18">; // false

组合检查

实际的验证器会交集组合多个条件:非空分段、允许的令牌以及结构平衡。每个条件都是条件类型,请使用逻辑风格的辅助类型将它们组合起来。

type And<A, B> = A extends true ? (B extends true ? true : false) : false;

递归限制

类型级递归具有深度限制。对于非常长的字符串,编译器可能会报错:“类型实例化过深”。请限制已解析输入的长度,或简化语法。

优于运行时解析

运行时解析器只有在计算错误字符串时才会报错。编译时验证会在您输入字面量的瞬间拒绝它,并提供完整的编辑器反馈,同时不会产生任何运行时开销。

为何重要

许多 DSL 接受字符串输入(路径、查询和格式)。在类型系统中验证它们的结构,可以在程序运行之前捕获拼写错误和格式错误的表达式,将一类运行时错误转变为编译错误。

快速检查

请检查您对编译时输入验证的理解。

回顾

您通过使用模板字面量类型和 infer 解析字符串字面量,并使用条件类型检查分段和操作符,在运行时之前验证了 DSL 输入。将函数参数约束为有效性类型后,格式错误的表达式会解析为 never 并导致编译失败,同时还需要注意递归限制。

常见问题解答

「编译时输入验证」课时是免费的吗?

是的 — 「编译时输入验证」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。

「编译时输入验证」这节课中我会学到什么?

在运行时之前拒绝格式错误的 DSL 表达式。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「编译时输入验证」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 TypeScript Academy 课中编写并运行代码吗?

能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 什么是类型级 DSL
  2. 设计流式查询 DSL
  3. 编译时输入验证
  4. 类型级 DSL 中的错误消息
← 返回 TypeScript Academy