Effect Duration.Input 升级:DurationObject 支持 Temporal 风格对象输入的实现解析
Effect Duration.Input 升级DurationObject 支持 Temporal 风格对象输入的实现解析【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code本文基于 t3code 仓库内嵌的 effect-smol 仓库位于.repos/effect-smol/中一份真实的 changeset 变更说明展开系统讲解Duration输入模型新增DurationObject这一 Temporal 风格对象输入的动机、类型定义、源码级解码实现与测试验证。读完本篇你可以掌握 EffectDuration.Input的完整输入形态理解对象式时长如{ hours: 1, minutes: 30 }如何被精确换算、舍入与规范化并能在自己的 Effect 项目里正确选用fromInput与fromInputUnsafe两个转换入口。变更背景一份 changeset 说明了什么本次讲解的核心文档是 t3code 仓库内 effect-smol 仓库的变更说明文件 duration-temporal-object-input.md其原文内容如下--- effect: patch --- Add DurationObject to Duration.Input to support Temporal-style object input. Durations can now be created from objects with named unit properties like { hours: 1, minutes: 30 }, similar to Temporal.Duration.from(). Supported fields: weeks, days, hours, minutes, seconds, millis, micros, nanos.从这份 changeset 可以直接读出三个关键事实变更级别为 patchfrontmatter 中effect: patch表明这是对effect包的兼容性增强不破坏既有 API目标是扩展Duration.Input联合类型新增成员DurationObject让带命名字段的时间单位对象成为合法输入语义上对标 ECMAScript Temporal 提案中的Temporal.Duration.from()字段集合changeset 列出了weeks、days、hours、minutes、seconds、millis、micros、nanos八类命名单位。需要注意的一个细节changeset 的措辞早于最终实现其中亚毫秒单位写作millis/micros/nanos而当前仓库源码中实际落地的接口字段名是milliseconds、microseconds、nanoseconds见下文类型定义。本文一律以当前仓库源码为准。这份变更目前处于 effect-smol 的 4.0.0 预发布pre流程中——pre.json 显示mode: pre, tag: rc说明DurationObject相关能力随 4.0.0 rc 版本线发布类型声明中也标注了since 4.0.0。DurationObject 类型定义与完整 Input 联合类型DurationObject的完整定义位于 Duration.tsexport interface DurationObject { readonly weeks?: number | undefined readonly days?: number | undefined readonly hours?: number | undefined readonly minutes?: number | undefined readonly seconds?: number | undefined readonly milliseconds?: number | undefined readonly microseconds?: number | undefined readonly nanoseconds?: number | undefined }所有字段均为可选且相互叠加additive任意子集组合都合法{ seconds: 1 }、{ days: 1, hours: 2 }或仅{ nanoseconds: 500 }都能构造出有效时长。接口注释明确写道 Compatible with Temporal.Duration-like objects见 Duration.ts L182-L212即设计目标是让持有 Temporal 风格时长对象的代码可以直接传入 Effect API。DurationObject作为新成员被并入Duration.Input联合类型Duration.ts L172-L180完整的输入形态如下输入形态TypeScript 类型语义已有时长Duration原样返回毫秒数number按毫秒解释纳秒数bigint按纳秒解释高精度二元组readonly [seconds: number, nanos: number]秒 纳秒对齐hrtime风格时长字符串${number} ${Unit}如10 seconds单位见Unit类型无穷字符串Infinity/-Infinity正/负无穷时长对象本次新增DurationObject命名单位字段叠加其中Unit类型Duration.ts L129-L145支持单复数混写如nano/nanos、micro/micros、milli/millis直至week/weeks。解码实现fromInputUnsafe 的对象分支所有输入形态最终由fromInputUnsafe统一解码。其对象分支Duration.ts L287-L318是本次变更的核心源码逻辑可归纳为四层第一层Duration 实例短路。若对象上带有 Duration 的 TypeId~effect/time/Duration直接返回原实例不做任何换算if (TypeId in input) return input as Duration第二层二元组分支。数组输入按[seconds, nanos]解释带完整的边界处理长度不为 2 或非数字字段时走invalid抛错两个分量含NaN时返回zero任一分量为-Infinity返回负无穷为Infinity返回正无穷否则以roundTiesAwayFromZero(input[0] * 1_000_000_000 input[1])归一化为纳秒。第三层DurationObject 字段叠加本次新增。各命名单位先被折算到毫秒整数轴上Duration.ts L305-L317const obj input as DurationObject let millis 0 // we can use truthy checks here, because 0 can be ignored if (obj.weeks) millis obj.weeks * 604_800_000 // 1 周 7 * 86_400_000 if (obj.days) millis obj.days * 86_400_000 // 1 天 24 * 3_600_000 if (obj.hours) millis obj.hours * 3_600_000 if (obj.minutes) millis obj.minutes * 60_000 if (obj.seconds) millis obj.seconds * 1_000 if (obj.milliseconds) millis obj.milliseconds if (!obj.microseconds !obj.nanoseconds) return make(millis) return make(roundTiesAwayFromZero( millis * 1_000_000 (obj.microseconds ?? 0) * 1_000 (obj.nanoseconds ?? 0) ))这里有三个值得注意的实现细节truthy 检查而非! null源码注释说明0值可以安全忽略因为0 * 单位对累加结果无影响代码因此保持简洁快速路径当输入不含亚毫秒字段microseconds/nanoseconds时直接以纯毫秒值调用make(millis)避免一次大整数乘法与舍入亚毫秒精度路径一旦存在microseconds或nanoseconds整体换算到纳秒轴——毫秒部分乘以1_000_000、微秒部分乘以1_000、纳秒直接相加——再交给roundTiesAwayFromZero做四舍五入到最近纳秒ties away from zero平局远离零方向舍入。第四层非法输入兜底。走到分支末尾仍未匹配任何形态的输入会落入invalid(input)抛出Invalid Input: ...错误Duration.ts L323-L325。roundTiesAwayFromZero本身定义在 Duration.ts L38-L39const roundTiesAwayFromZero (input: number): bigint BigInt(input 0 ? Math.ceil(input - 0.5) : Math.floor(input 0.5))即对正数向下加 0.5 取整、对负数向上加 0.5 取整保证±0.5平局时统一向绝对值增大方向舍入。这一规则与Input类型文档中 Finite fractional values that are normalized to nanoseconds are rounded to the nearest nanosecond, with ties away from zero 的声明一致。类型文档中的行为示例DurationObject接口的 jsdoc 内嵌了三个行为示例Duration.ts L190-L198import { Duration } from effect Duration.fromInputUnsafe({ seconds: 30 }) // Duration.seconds(30) Duration.fromInputUnsafe({ days: 1 }) // Duration.days(1) Duration.fromInputUnsafe({ seconds: 1, nanoseconds: 500 }) // Duration.nanos(1_000_000_500n)第三个示例值得品味{ seconds: 1, nanoseconds: 500 }的结果是Nanos 形态1_000_000_500n而非 Millis 形态——由于存在亚毫秒成分整条换算被提升到纳秒轴最终时长保留了500n纳秒的尾部精度。这说明对象的输出形态由输入是否含亚毫秒字段决定而不是固定输出毫秒。安全入口 fromInput 与错误边界fromInputUnsafe的语义是输入可信、非法即抛错。当输入来源不可信如用户配置、远端请求体时应使用fromInput它通过Option.liftThrowable将抛错转换为OptionDuration.ts L343-L345export const fromInput: (u: Input) Option.OptionDuration Option.liftThrowable( fromInputUnsafe )文档给出的示例行为Duration.fromInput(1000) // Option.some(Duration.seconds(1)) Duration.fromInput(invalid as any) // Option.none()从源码结构看fromInput对DurationObject输入同样适用一个字段名拼写错误例如误用 changeset 早期措辞里的millis的对象虽然不会抛错未知字段被忽略、合法字段照常累加但会导致时长静默变短——这是对象式输入相比字符串输入更需要配套 Schema 校验的原因。在 Effect 生态中这类边界通常由调用方在Schema层完成字段白名单校验后再交给fromInput做兜底转换。测试验证effect-smol 的测试文件 Duration.test.ts 中包含针对对象输入的断言例如deepStrictEqual(Duration.fromInputUnsafe({ seconds: 30 }), Duration.seconds(30))Duration.test.ts L76以及多字段叠加的场景Duration.test.ts L108Duration.fromInputUnsafe({ days: 1, hours: 2, minutes: 30, seconds: 15 })测试覆盖了单一字段与等价构造器一致和多字段叠加两条主线与上文源码中millis累加逻辑一一对应。变更溯源与相关配套改动从 CHANGELOG.md 可以确认该变更的合并信息PR #1696commit5a84853贡献者 krzkaczorAddDurationObjecttoDuration.Inputto support Temporal-style object input正文与 changeset 文件逐字一致即本文开头的字段清单就是该 PR 的发布说明同一条变更线还包含PR #1701commit21d5d5eallow assigning Temporal types to DateTime Duration input——即在同一批 4.0.0 rc 变更中DateTime与Duration的输入类型同步放宽了对 Temporal 类型赋值的接受度。两者组合后Effect 的时间 API 在类型层面形成了一套与 Temporal 提案对齐的输入契约。在项目中如何使用与适用前提以当前仓库源码为准在 effect-smol 4.0.0 rc 之后的版本中任何接受Duration.Input的 Effect API延迟、超时、TTL、调度间隔等都可以直接传入命名单位对象import { Duration, Effect } from effect // Temporal 风格对象输入 const backoff Duration.fromInputUnsafe({ minutes: 5, seconds: 30 }) // 等价于 5 分 30 秒的毫秒时长 // 含亚毫秒精度时输出纳秒形态 const precise Duration.fromInputUnsafe({ seconds: 1, nanoseconds: 500 }) // Duration.nanos(1_000_000_500n) // 不可信输入走安全路径 const parsed Duration.fromInput({ hours: 1, milliseconds: 250 })适用前提与限制需要明确版本前提DurationObject与扩展后的Input联合类型均标注since 4.0.0Duration.ts L170且 effect-smol 当前处于rc预发布模式pre.json尚未到稳定版的项目应在升级前留意 rc 阶段可能存在的接口微调字段名以源码为准亚毫秒字段名为milliseconds/microseconds/nanosecondschangeset 文本中的millis/micros/nanos是早期措辞未知字段被静默忽略解码只读取白名单字段拼写错误不会报错建议在上游用 Schema 或Struct校验字段集合叠加语义所有字段为正负相加负数分量合法并参与远离零方向的舍入。参考文件索引文件作用duration-temporal-object-input.md本次变更的 changeset 原文patch 级别说明Duration.tsDurationObject、Input类型与fromInputUnsafe/fromInput实现Duration.test.ts对象输入的测试断言CHANGELOG.mdPR #1696/#1701 的合并记录pre.jsoneffect-smol 当前处于 pre/rc 发布模式的配置【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考