
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),僅供參考