
Effect Schema 数值域建模统一新增 Schema.Natural 与正规定式化数值 Schema 全解析【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect本文基于 Effect 仓库中的变更集 canonical-number-schemas.md深入解析 Effect 4.x 在 Schema 模块中引入的Schema.Natural非负安全整数Schema以及围绕Schema.Int、Schema.Finite、Schema.Natural的正规定式化canonical重构它覆盖了 Effect 核心、AI 协议包与 OpenAPI 补丁工具中所有数值域值的建模同时修正了Schema.NumberFromString的解码类型并让Schema.DurationFromMillis与Schema.DurationFromNanos支持负持续时间。读完后你将掌握如何选择正确的数值 Schema、理解底层过滤与编解码实现并了解这些变更对 date、time-zone、cluster、event-log、persistence、socket、SQL、DevTools 等模块 Schema 的实际影响。变更背景一次跨包的 patch 级统一该变更集的文件头声明了受影响的包与变更级别均为patcheffect核心包effect/ai-anthropic、effect/ai-openai、effect/ai-openai-compat、effect/ai-openrouterAI 协议包effect/openapi-generatorOpenAPI 补丁工具正文说明了本次变更的两个核心动作新增Schema.Natural表示非负安全整数non-negative safe integers并在 Effect 核心、AI 协议、OpenAPI 补丁中统一使用Schema.Int、Schema.Finite、Schema.Natural这三个“正规定式化”Schema 来建模数值域值修正既有 Schema 的数值约束更新 date、date-time、file、time-zone、cluster、event-log、persistence、socket、SQL 和 DevTools 相关 Schema在合适的位置拒绝非法的非有限数non-finite或非整数值同时修正Schema.NumberFromString的解码后 Schema并允许Schema.DurationFromMillis与Schema.DurationFromNanos表示负持续时间。这类“规范 Schema”的意义在于过去各模块可能各自用Schema.Number.check(...)或Schema.Int.check(...)手写不同约束行为口径不一统一后凡是“计数、序号、大小、时长、有限浮点”这类域值都有一致的校验语义、JSON Schema 映射与 Arbitrary 生成约束。Schema.Natural非负安全整数的正规定义定义与实现Schema.Natural在 4.0.0 版本新增其定义位于 Schema.tsexport const Natural: Natural Int.check(isGreaterThanOrEqualTo(0))它构建在Schema.Int之上而Schema.Int本身3.10.0 引入见 Schema.ts是export const Int: Int Number.check(isInt())两层过滤的语义isInt()见 Schema.ts校验谓词为Number.isSafeInteger(n)即只接受安全整数范围JS 可精确表示的整数内的值NaN、Infinity、-Infinity与小数值全部拒绝其 JSON Schema 映射为type: integerArbitrary 生成时应用number: integer约束isGreaterThanOrEqualTo(0)在整数基础上追加非负约束0是合法值。类型层面Natural接口继承自Intexport interface Natural extends Int即它复用Int的全部类型能力并进一步收窄。源码文档注释给出的使用场景非常明确“Use when you need a count, index, or size that cannot be negative.”——任何计数、索引或尺寸字段都应优先使用它。测试用例验证的行为边界Schema.test.ts 中的Natural测试固化了其判定行为输入解码结果失败信息0成功—1成功—-1失败Expected a value greater than or equal to 01.1失败Expected an integer编码方向encode同样被校验0可编码-1会失败。此外在 SchemaBinary.test.ts 中可以看到Schema.Natural参与二进制编解码encode(Schema.Natural, 1)产生字节序列[2, 0x20, 2]说明它被纳入了统一的 Schema 编码体系。仓库内的实际落地场景统一后的Schema.Natural已在仓库多处取代手写的非负整数约束典型场景包括EventLog / EventJournal序列号必须是天然数如 EventJournal.ts 的remoteSequence: Schema.Natural、EventLogEncryption.ts 的sequence: Schema.Natural以及 EventLogMessage.ts 中的part: Schema.Tuple([Schema.Natural, Schema.Natural]).check(...)SQL 层SqlError.ts 中expected: Schema.Natural, actual: Schema.Natural——行数这类字段不可能为负DevToolsDevToolsSchema.ts 中指标的buckets、count等统计量全部使用Schema.NaturalOpenAPI 补丁工具OpenApiPatch.ts 中operationIndex: Schema.NaturalAI 工具定义示例20_tools.ts 展示了带默认值与注解的用法maxResults: Schema.Natural.pipe(Schema.withDecodingDefault(Effect.succeed(10)))——maxResults、available这类“可用数量”字段用Natural建模语义上杜绝了负数输入。这些落点正好对应变更集中“use canonical ... schemas ... across Effect, AI protocols, and OpenAPI patches”的表述。正规定式化数值 Schema 体系Int、Finite、Natural 的分工统一的数值域 Schema 家族由三个基元构成各有明确的适用边界Schema语义拒绝的值定义位置Schema.Int安全整数可正可负非整数、NaN、±InfinitySchema.tsSchema.Finite有限浮点数NaN、Infinity、-InfinitySchema.tsSchema.Natural非负安全整数含 0负数、非整数、NaN、±InfinitySchema.tsSchema.Finite直接由底层 AST 节点构造make(SchemaAST.finite)3.10.0 引入配套的isFinite()校验器文档明确说明其 JSON Schema 语义“This check does not have a direct JSON Schema equivalent, but ensures the number is valid and finite.”而在 Arbitrary 生成时应用有限数约束见 Schema.ts。选型建议基于源码注释的“When to use”与“See”指引计数、索引、长度、序号、行号→Schema.Natural不可为负可能为负的整数如偏移量、差值、端口方向的有符号量→Schema.Int任意有限浮点如比率、坐标、权重→Schema.Finite需要更窄范围时可在此基础上叠加过滤如isInt32()映射 OpenAPI 3.1 的format: int32与isUint32()format: uint32见 Schema.ts。NumberFromString 的解码修正与 FiniteFromString 的分离变更集提到“Correct the decoded schema ofSchema.NumberFromString”。从当前源码看修正后的定义位于 Schema.tsexport const NumberFromString: NumberFromString String.annotate({ expected: a string that will be decoded as a number }).pipe(decodeTo(Number, SchemaTransformation.numberFromString))其类型接口声明解码目标为裸NumberdecodeToNumber, String文档注释解释了行为细节解码时按 JavaScript 数值强制转换包括可能产生非有限值NaN、Infinity、-Infinity编码方向则把数值编码为字符串。也就是说NumberFromString的职责被收敛为“字符串 ↔ 任意 number”的纯粹格式转换不再隐含有限性假设。如果业务上需要拒绝非有限值应使用配套的Schema.FiniteFromString4.0.0 新增见 Schema.tsexport const FiniteFromString: FiniteFromString String.annotate({ expected: a string that will be decoded as a finite number }).pipe(decodeTo(Finite, SchemaTransformation.numberFromString))二者复用同一个numberFromString转换区别仅在解码目标的约束NumbervsFinite。这体现了本次规范化的核心思路格式转换与域约束解耦——先做字符串解析再显式选择数值域 Schema。DurationFromMillis 与 DurationFromNanos支持负持续时间变更集明确“allowSchema.DurationFromMillisandSchema.DurationFromNanosto represent negative durations.” 负时长在 Effect 中是合法的用于表示相对过去的偏移如调度延迟补偿、回溯窗口。DurationFromNanosbigint 纳秒定义见 Schema.tsexport const DurationFromNanos: DurationFromNanos BigInt.pipe( decodeTo(Duration, durationFromNanos) )其底层转换Schema.ts中解码方向直接Duration_.nanos(i)对负bigint不做拦截编码方向通过Duration_.toNanos(a)返回Option判断可表示性——Duration.infinity与Duration.negativeInfinity这类无法用纳秒表示的时长会在编码时失败expected: a Duration representable as a bigint。文档注释完整描述了这一边界。DurationFromMillisnumber 毫秒定义见 Schema.tsexport const DurationFromMillis: DurationFromMillis Number.pipe( decodeTo(Duration, durationFromMillis) )其语义比 nanos 版本更宽松文档注释指出“finiteor infinitenumber is decoded as aDuration”即Infinity/-Infinity分别映射为无限时长另有一个明确的 Gotcha——NaN被解码为Duration.zero与Duration.millis的行为保持一致。同目录下的字符串变体Schema.DurationFromString接受任何Duration.fromInput可解析的格式见 Schema.ts则继续承担人类可读时长如10 seconds的解析职责。这三个 Duration Schema 的分工DurationFromString字符串格式、DurationFromMillis毫秒数值含无限值、DurationFromNanos纳秒 bigint精确但仅有限值可编码在负时长上均已对齐支持。跨模块影响拒绝非法非有限/非整数值变更集后半句列出了被更新的模块范围“the date, date-time, file, time-zone, cluster, event-log, persistence, socket, SQL, and DevTools schemas to reject invalid non-finite or non-integer values where appropriate.”结合仓库中Schema.Natural的使用分布可以印证这一范围event-logEventJournal.ts、SqlEventJournal.ts、SqlEventLogServerUnencrypted.ts 等处的序列号字段统一为Schema.NaturalSQLSqlError.ts 的行数字段DevToolsDevToolsSchema.ts 中occurrences: Schema.ReadonlyMap(Schema.String, Schema.Natural)等统计结构persistence / cluster这两个模块的 Schema 与 event-log、SQL 存储层共享同一套持久化协议序列号与分片计数同样落入Natural的约束之下从源码结构看其协议消息复用上述 event-log / SQL Schema。“where appropriate”这一限定很重要并非所有 number 字段都强制收紧而是语义上属于计数/序号/尺寸/有限量的字段才切换到规范 Schema避免把合法的负值或浮点值误判为非法输入。实践要点小结建模顺序先判断域整数非负整数有限浮点再选基元 SchemaNatural/Int/Finite最后按需叠加范围过滤如isInt32()、isBetween字符串解析与域约束分离JSON 字符串数字用NumberFromString允许非有限值或FiniteFromString拒绝非有限值不要依赖解析 Schema 隐式收窄时长字段纳秒精度且要求有限值用DurationFromNanos毫秒且可能为无限值用DurationFromMillis人类可读格式用DurationFromString三者均支持负时长验证手段本仓库 Schema.test.ts 等测试展示了如何断言解码/编码的通过值与失败消息如Expected a value greater than or equal to 0可作为自研 Schema 测试的参照模板。本次变更属于 patch 级别Schema.Natural是纯新增导出既有 API 的行为修正NumberFromString解码类型、Duration Schema 的负值支持都是对“应当如此”的语义回归从源码与测试用例看升级后原有合法输入的行为保持不变非法输入非有限数、负计数会被更早、更一致地拒绝。【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考