Effect Schema 怎么校验长度、范围和格式?

TypeScript 类型能表达「这是个数字」,表达不了「这是个 1 到 150 之间的整数」。一个字段是字符串,也不等于它可用:空字符串、不像邮箱的文本,类型照样放行。

答案是:用 Schema.check 在基础类型上附加约束,比如 Schema.isBetween、Schema.isMinLength、Schema.isPattern。 这些约束在解码时一并检查,数据一旦通过,你就知道它不只是「某个字符串」,而是「非空的字符串」。

Schema 是 Effect 里把运行时校验和 TypeScript 类型合成一份定义的工具,基础用法见 为什么不能相信 TypeScript 类型。下面看怎么写约束,以及它们放在哪。

怎么给数字、字符串加约束?

import { Schema } from "effect"

const Age = Schema.Int.check(Schema.isBetween({ minimum: 0, maximum: 150 }))
const Name = Schema.String.check(Schema.isMinLength(1))
const Email = Schema.String.check(Schema.isPattern(/^[^@]+@[^@]+$/))

Age 要求整数且在 0 到 150 之间,Name 要求至少 1 个字符,Email 要求匹配给定的正则。

约束什么时候会被检查?

在解码时。用 Schema.decodeUnknownEffect 解码外部数据,形状和约束一起检查,不合法就以类型化的 SchemaError 失败,可以在边界处翻译成领域错误,见 错误设计。

约束该写在哪?

写进 Schema,而不是散落在业务代码里。字段是字符串不等于字段可用,该有的长度、范围、格式都应该在边界解码时一次性检查。这样内部函数可以直接信任类型,不必重复校验。把约束和转换、品牌类型结合起来的建模方式,见 Schema 建模。

本文内容沿用自我之前写的 Effect 教程章节,该章节没有标注 effect 的版本号,也没有记录这些代码的运行结果,所以这里不声称在某个版本上验证过。新版本的 Schema API 与旧版差异很大,请对照你所用版本的文档确认。