news 2026/10/15 16:22:50

ts-toolbelt 9.6.0 版本更新解析:AutoPath 自定义分隔符、Narrow 方差修复与函数组合类型系统的深度改进

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ts-toolbelt 9.6.0 版本更新解析:AutoPath 自定义分隔符、Narrow 方差修复与函数组合类型系统的深度改进
  • 开发工具

【免费下载链接】ts-toolbelt

👷 TypeScript's largest type utility library

项目地址:https://gitcode.com/gh_mirrors/ts/ts-toolbelt
点击查看免费下载

本篇基于 CHANGELOG.md 中记录的 9.6.0(2021-03-10)发布条目展开,逐条对照 sources 下的类型源码与 tests 下的类型测试,讲解该版本在路径自动补全(AutoPath)、参数窄化(Narrow)、函数组合(Compose)、路径操作(O.Paths / O.P)等模块中引入的能力与修复,帮助你在升级到 9.6.0 时准确判断这些改动对现有类型代码的影响,并学会利用新增的自定义分隔符参数编写更安全的类型路径。

ts-toolbelt 是 TypeScript 的类型工具库(当前仓库版本即 9.6.0,见 package.json),其 CHANGELOG 由 standard-version 依据 Conventional Commits 提交规范自动生成。9.6.0 的核心主线是"让路径类类型更准确、让函数类型更可控":为F.AutoPath增加了自定义分隔符参数,修复了F.Narrow在数组推断、方差(variance)与高阶函数场景下的缺陷,并允许柯里化函数参与F.Compose组合。

版本概览与发布机制

条目内容
版本号9.6.0
发布日期2021-03-10
变更来源CHANGELOG.md,由 standard-version 生成
提交规范.commitlintrc.json扩展@commitlint/config-conventional,即常规提交约定
变更分类Features(新特性)、Bug Fixes(缺陷修复)、Others(重构与版本号维护)

从 package.json 的 devDependencies 可见standard-version@^9.1.0是版本管理工具,实际发布流程封装在 scripts/release.sh 中:

  • 先执行npm run test确保全部类型测试通过;
  • 用node -p判断package.json中版本号的 patch 位是否为0,以此决定是否属于正式发布;
  • 非 master 分支执行npx standard-version --skip.tag(只生成 changelog 不打 tag);
  • master 分支且非正式发布时同样--skip.tag;正式发布时执行完整npx standard-version并git push origin $BRANCH --follow-tags。

因此 CHANGELOG 中大量 "release: 9.5.x" 的 Others 条目,是这一自动发布流程在 9.5.2~9.6.0 之间的中间产物,它们在 9.6.0 发布时被合并进同一份变更记录。

新特性:F.AutoPath 支持自定义分隔符

本次唯一标注为 Features 的变更,是为AutoPath增加路径分隔符参数。AutoPath位于 sources/Function/AutoPath.ts,其公开签名是:

export type AutoPath<O extends any, P extends string, D extends string = '.'> = _AutoPath<O, P, D>;

三个参数的语义分别为:

  • O:待探测路径的对象类型;
  • P:当前已输入的路径字符串;
  • D(可选,默认'.'):路径的分隔符。

在 9.6.0 之前,路径只能以.分隔;现在可以传入任意字符串作为分隔符。实现上,_AutoPath通过Split<P, D>将已输入路径按分隔符拆成索引列表,再配合内部的MetaPath(把对象递归映射为"路径字符串联合")与ExecPath/NextPath(在元路径上按索引取值并过滤出下一步可达路径)完成自动补全。这一机制在 tests/Function.ts 中有完整的验证用例,例如:

check<F.AutoPath<O_AUTOPATH, 'b/b/0/a', '/'>, 'b/b/0/a' | 'b/b/0/a/a', Test.Pass>(),

O_AUTOPATH中b.b是O_AUTOPATH[]数组,测试确认用/作为分隔符同样能命中数组下标0并给出后续可补全路径;而check<..., 'b.b.0.a' | 'b.b.x.a.a', Test.Fail>()则验证错误路径会被排除。配套的典型用法(来自源码注释)是声明一个基于AutoPath的取值函数:

declare function get<O extends object, P extends string>( object: O, path: AutoPath<O, P> ): Path<O, Split<P, '.'>> // 合法:friends 是数组,40 为下标 const friendName = get(user, 'friends.40.name') // 报错:names 并非有效字段 const friendNames = get(user, 'friends.40.names')

F.AutoPath 系列修复:分发、原始类型属性与空路径

9.6.0 同时修复了f.autopath的三个问题,三者都聚焦于补全候选的精确性:

  1. distribute(分发):确保AutoPath在对象为联合类型时按联合成员分发处理,避免只取联合中的一个分支导致补全缺失;
  2. do not show primitive props(不再展示原始类型的属性):此前AutoPath可能把string/number等原始类型的内建属性(如length、toString)也作为补全候选,修复后只枚举用户数据结构自身的路径;
  3. no primitive paths(排除原始类型路径):与上一条配合,避免Primitive内部路径污染补全结果。

这与MetaPath的实现相互印证:MetaPath递归展开[K in keyof O]时会把每个子属性映射成Join<[...P, KeyToIndex<K, SP>], D>与更深的MetaPath的联合,而NextPath通过Exclude<OP, string>剔除直接的字符串路径后再Select<..., string>取得下一级路径,从而保证只提示结构内可达的字段。若你从旧版本升级后补全提示变少,很可能正是这些"本不该出现"的原始类型路径被正确移除了。

F.Narrow 系列修复:方差、数组推断与高阶函数

9.6.0 对F.Narrow(见 sources/Function/Narrow.ts)做了密集修复,集中解决"泛型参数被拓宽(widening)"的经典痛点:

  • variance(方差):包括fix variance and array inference、variance与revert variance fixes,前两者修正Narrow在函数参数协变/逆变场景下的行为,后者说明部分方案被回退,属于实现层面的试错与收敛;
  • higher order function support(高阶函数支持):Narrow现在能正确处理作为参数传入的函数类型;
  • preserve fns / preserve functions(保留函数):窄化过程中函数类型的成员不再被展开破坏,preserve fns and better display还改进了类型在编辑器中的展示效果。

Narrow的实现核心是NarrowRaw:对[]直接返回、对Narrowable(string | number | bigint | boolean,见 sources/Function/_Internal.ts)原样保留,其余对象则递归映射,且遇到Function成员时保留原类型而非继续深入。测试 tests/Function.ts 验证:

declare function narrowList<A extends any[]>(x: F.Narrow<A>): A; const test05 = narrowList(['e', 2, true, {f: ['g', ['h']]}]) // typeof test05 === ['e', 2, true, {f: ['g', ['h']]}],字面量被完整保留

也就是说,F.Narrow能让['e', 2, true]这类实参在推断时保持为精确的字面量元组,而不是拓宽成(string | number | boolean)[],这是实现"不可变配置对象字面量类型"的常用手段。

函数组合:F.Compose 允许柯里化函数参与

变更fn: allow for curried in compose意味着F.Compose组合的函数可以是普通函数或柯里化(Curry)函数。入口类型定义在 sources/Function/Compose.ts:

export type Compose<mode extends Mode = 'sync', input extends Input = 'multi'> = IntersectOf<{ 'sync': { 'multi': ..., 'list': ... }, 'async': { ... } }[mode][input]>

其中Mode = 'sync' | 'async'、Input = 'multi' | 'list'(见 sources/Function/_Internal.ts)。每个具体实现(如 sources/Function/Compose/List/Sync.ts)的每个重载都同时接受Function<...>与Curry<Function<...>>,例如:

(fns: [Function<[R0], R1> | Curry<Function<[R0], R1>>, Function<P, R0> | Curry<Function<P, R0>>,]): Function<P, R1>

测试 tests/Function.ts 展示了实际效果——柯里化函数curry((a1: number, d2: number) => \${a1 + d2}`)与普通函数一起被composeSync接受并正确推导出最终签名;异步版本 [sources/Function/Compose/List/Async.ts](https://link.gitcode.com/i/f6dc613b1a2fcb24537f4a4411d5893c) 则在每层用Await解开Promise后再传入下一层,最终返回Promise<Await >,从而让F.Compose<'async'>的链式推导与await` 语义完全对齐。

O.Paths 深入数组:路径枚举覆盖数组元素

修复o.paths: dive within arrays and deeper使O.Paths能够下探到数组元素内部的路径。核心实现见 sources/Object/Paths.ts:

type _Paths<O, P extends List = []> = UnionOf<{ [K in keyof O]: O[K] extends BuiltIn | Primitive ? NonNullableFlat<[...P, K?]> : [Keys<O[K]>] extends [never] ? NonNullableFlat<[...P, K?]> : 12 extends Length<P> ? NonNullableFlat<[...P, K?]> : // 实例化深度上限 _Paths<O[K], [...P, K?]> }>

递归时若子属性是BuiltIn/Primitive或没有可枚举 key 则停止下探,否则继续递归并把当前 key 追加进路径。值得注意的是12 extends Length<P>——这是源码中为控制类型实例化深度而设置的路径长度上限(12 层),避免深度嵌套类型引发实例化过深错误。测试 tests/Object.ts 确认{prop: {a: 1}[]}可枚举出['prop', number, 'a']形式的路径,即数组元素属性也被纳入路径联合;CHANGELOG 中同期的string: instantiation limiters(字符串工具加入实例化限制器)也是同类"深度/性能防护"思路的体现,例如 sources/String/Split.ts 通过__Split递归加Cast完成分隔拆分。

路径操作重实现:O.P 模块与更灵活的 List 键

9.6.0 的 Others 部分还包含两次结构性改动:

  • o.p: re-implement(O.P 模块重实现):O.P(Path)命名空间下的操作被整体重写。以 sources/Object/P/Merge.ts 为例,Merge<O, Path, O1, depth = 'flat'>通过MergeAt沿Path递归定位,路径末端用OMerge(支持'flat' | 'deep'深度模式)合并字段;sources/Object/P/Update.ts 的UpdateAt则在路径末端区分List与object,分别调用 sources/List/Update.ts 与OUpdate完成更新。重实现后的行为由 tests/Object.ts 验证,包括对路径段为联合('a' | 'b')时的分发处理,以及O.P.Update对深层可变路径的支持。
  • list: more flexible keys(List 键更灵活):List 相关类型对键的约束放宽,例如 sources/List/Update.ts 中Update<L, K, A>将K同时归一化为`${K & number}` | K,从而同时兼容数字索引与字符串键。

升级到 9.6.0 的实操要点

  1. 分隔符参数:使用F.AutoPath<O, P, D>时可按需传入D(如'/'),默认仍为'.',旧代码无需改动即可升级。
  2. 补全行为变化:若依赖F.AutoPath的编辑器提示,升级后原始类型内建属性将不再出现在候选中,这是有意为之的修复,请勿视为回归。
  3. Narrow 更可靠:涉及数组字面量、高阶函数参数的F.Narrow场景,升级后可获得更精确的字面量推断,同时可关注编辑器中类型展示的改善。
  4. Compose 组合柯里化函数:F.Compose同步/异步、multi/list 四种组合均接受Curry包裹的函数,可放心混用。
  5. 深度上限提示:O.Paths存在 12 层深度上限(见 sources/Object/Paths.ts),设计超深数据结构时应考虑路径枚举的边界。

所有上述行为均在 tests/Function.ts 与 tests/Object.ts 中有对应check断言,升级后运行npm run test(内部执行 scripts/test/all.sh)即可在本仓库验证这些类型的正确性。

  • 开发工具

【免费下载链接】ts-toolbelt

👷 TypeScript's largest type utility library

项目地址:https://gitcode.com/gh_mirrors/ts/ts-toolbelt
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 16:22:35

安卓17 Beta待机耗电修复实测:主力机升级决策与回退指南

1. 安卓新版本Beta推送背后&#xff0c;普通用户最该关心的三件事每次安卓大版本Beta推送&#xff0c;社交平台上总有两拨人吵得不可开交。一拨是拿着主力机第一时间冲进去的尝鲜派&#xff0c;另一拨是看着各种"翻车"反馈庆幸自己没动手的保守派。这次安卓17 Beta更…

作者头像 李华
网站建设 2026/10/15 16:21:41

江门蓬江合金怪兽轮毂修复:大众化价格,打造高端轮毂修复品质

汽车轮毂就相当于汽车的 “双脚”&#xff0c;日常行车时&#xff0c;马路牙子剐蹭、坑洼路面撞击、刹车粉尘腐蚀、长期日晒氧化&#xff0c;都很容易造成轮毂划痕、掉漆、缺口、变形甚至开裂。很多江门车主遇到轮毂受损&#xff0c;第一时间会纠结到底是直接换新轮毂&#xff…

作者头像 李华
网站建设 2026/10/15 16:21:36

BLE与SPP双模安卓蓝牙串口助手源码实战:从协议栈到APK

简介&#xff1a;BLE_SPP 安卓手机蓝牙串口助手源码面向 Android 开发者与物联网硬件调试人员&#xff0c;基于 Android Studio 实现手机与 BLE 设备之间的串口式数据交互&#xff0c;可用于智能穿戴、健康监测、智能家居等场景的通信调试与二次开发。压缩包共 1946 个文件&…

作者头像 李华
网站建设 2026/10/15 16:21:28

编译原理公开课学习指南:从词法分析到三地址码的完整实践

语言这个东西&#xff0c;是人写的&#xff0c;也是机器读的。日常工作里我们每天都在用别人设计好的编程语言&#xff0c;但有多少人想过&#xff0c;自己敲下的那行代码&#xff0c;是怎么从一串字符变成CPU里一条条指令的&#xff1f;我自己的经历是&#xff1a;工作三四年后…

作者头像 李华
网站建设 2026/10/15 16:21:23

结婚证双认证公证需要什么材料?证天下一站式申办教程,附避坑指南

摘要&#xff1a;办理结婚证双认证公证&#xff0c;核心是准备夫妻双方身份证件、结婚证等资料&#xff0c;完成公证、外交部认证、目标国驻华使馆认证整套手续。很多人不清楚材料清单、办理流程&#xff0c;反复跑窗口耽误时间。大家可以在微信/支付宝搜索【证天下】小程序&am…

作者头像 李华
网站建设 2026/10/15 16:20:55

考研操作系统第一章:计算机系统概述的认知地图构建法

1. 这不是笔记搬运&#xff0c;而是考研操作系统复习的“认知地图”构建法“OS知识点汇总&#xff08;考研用&#xff09;——第一章&#xff1a;计算机系统概述”&#xff0c;光看标题&#xff0c;很多人第一反应是&#xff1a;又一本堆砌定义的速查手册&#xff1f;翻两页就困…

作者头像 李华