Decode pipeline
FieldCodec 的 decode 可以是普通函数。@guanriyue/decurl/decode 提供的是一组 helper,用来把常见解析步骤写成更短、更显式、更容易 review 的 pipeline。
这段 pipeline 表达了完整策略:先 trim,再要求整数形状,然后转换成 number,最后要求最小值为 1。
Decode step
每个 decode step 都是普通函数:
返回 null 或 undefined 表示当前 step 解析失败、值缺失或值无效。pipe 遇到失败结果会停止执行后续步骤。
失败结果如何回退到 defaultValue,属于 FieldCodec 层的职责;decode primitive 只负责表达“这个 raw value 能不能变成业务值”。
先 shape,再转换
推荐先用 shape 限定字符串形状,再做转换。
这样可以避免把 URL 中意外出现的值隐式转换成业务值。
这些转换对普通 JavaScript 是合法的,但在 URL search fields 中通常不够可审查。Decode pipeline 倾向于先声明哪些字符串形状可以进入业务层。
条件约束
elementOf 适合枚举值:
where 适合自定义 predicate 或 type guard:
startsWith、min、max、length 这类 helper 也都只做单一步骤。它们的目标不是成为完整 validation DSL,而是让常见 URL search params 约束更容易组合。
多值字段
URLSearchParams 允许同一个 key 出现多次:
多值字段的 decode 输入通常是 string[]。可以用 mapItems 对每一项执行 pipe-like decode,并自动过滤解析失败的项。
mapItems 的职责是 item decode 和过滤 null / undefined。如果需要排序、分组或其他数组级业务规则,可以把普通函数接到 pipe 后面。
TypeScript
Decode primitive 会保留 pipeline 的类型信息。elementOf 可以从内联数组字面量推导联合类型,不需要 as const。
边界
Decode primitive 只关心普通值的转换、过滤和组合。它不理解 URLSearchParams key,也不负责 alias、defaultValue、patch encode 或 React Router hooks。
这些边界分别由后续文档说明:
- FieldCodec 定义:单个字段如何使用
decode,以及defaultValue、encode、eq如何发挥作用。 - Search Fields:多个 field 如何组成一份 search object。
- URLSearchParams:Search Fields 如何 decode 和 patch encode URLSearchParams。
为什么不是成品 parser
Decurl 不提供 parseAsInteger()、parseAsDateRange() 这类成品 parser。URL 参数解析通常包含多个项目级选择,例如是否 trim、是否允许科学计数法、失败时如何处理。成品 parser 会把这些选择藏起来。
推荐把步骤写出来:
这比一个宽泛的 parser 更容易局部调整:
业务项目如果需要更短的写法,可以在项目内封装自己的函数:
这种封装带有业务上下文,比在通用 decode primitive 中隐藏策略更可控。
为什么使用它
自定义函数完全没问题。Decode primitive 不是 FieldCodec 的必需品,也不是 Decurl 强加给开发者的写法。你可以直接在 decode 里写任意解析逻辑;当数据结构复杂、解析步骤带有明显业务语义时,也更推荐把逻辑写成自己的函数。
Decode primitive 只是一个备选。它主要服务常见且简单的 URL search params 场景,例如分页、排序、筛选项、开关状态、资源 id。它更像一组描述性语言:用边界明确的小函数,把“这个 URL 字符串如何进入业务层”写出来。
这段代码比手写函数更短,但仍然能看到每一步。它不会偷偷 trim、不会偷偷接受宽松数字格式,也不会把 fallback 或 default 策略藏进 parser 里。
如果熟悉函数式编程,可以把 decode primitive 粗略类比为 Optional / Maybe 这类 monad 风格组合:每一步接收一个值,产出下一个值;null / undefined 被约定为“无效值”,后续步骤停止。这不是为了引入复杂概念,而是为了让小型解析部件可预测、可组合。
这也是为什么它比较接近 RxJS operator 或 lodash 小函数的设计取向:每个函数小而明确,组合后提升可读性。但 Decurl 会控制 primitive 的数量,不把它扩展成庞大的工具库。人类开发者难以记忆那么多工具函数。但在 AI coding 越来越常见的场景下,小型、命名清晰、边界稳定的 API 更容易被 agent 扫描和使用,也更容易被开发者 review。