is-kit 的 GitHub 星数到了 100。数字本身说明不了太多,但放在 50 星到 100 星这段区间里,有些变化比数字更值得说。
50 星时,作者想证明的是这个库不只是一个玩具。它已经被用在一个服务超过十万用户的 TypeScript 生产应用里,用来替代重复的运行时检查,并把 HTTP 错误、字面量联合、数组、API 返回值、普通对象等判断收成可复用的类型守卫。当时最重要的结论不是代码变短了,而是这些检查有了统一的形状:小守卫可以组合,应用自己的辅助函数可以夹在库和业务代码之间,组合结果仍然能参与正常的 TypeScript 控制流。这部分设计没有变。

变的是库本身,以及它被使用的方式。
一个反复出现的需求是属性精炼。手里已经有一个可信的类型守卫,比如判断字符串是否合法,但想表达的是"这个对象有一个属性,而且该属性是字符串"。听起来简单,实际要区分几种情况:必需属性和可选属性不同,数组下标和对象属性不同,可选属性在已知有值时怎么收窄、仍然可选时又怎么收窄,也不一样。is-kit 为此增加了三个属性精炼辅助函数,思路是把已有的守卫抬到属性或数组元素这一层,而不是在另一个自定义谓词里重写一遍。这符合库一贯的取向:不做一个大而全的校验器,做能反复用的小检查。
更大的新增是判别联合的穷尽校验 API。运行时验证一个判别联合并不难,难的是让 TypeScript 确认校验器本身覆盖了整个联合。新的构建器会在编译期检查缺失的分支、多余的分支、不兼容的分支守卫、不完整的判别元组。手写类型守卫最容易出的问题是漂移:TypeScript 类型改了,运行时守卫没改,编译器通常不会提醒。这个 API 就是在把这类错误变得难以发生。

除了新增功能,库也变得更严格。近期版本修正了字面量键收窄、原生品牌检查、带覆写迭代器的数组守卫、精确校验、symbol 键的 struct schema、跨 realm 的 struct schema 等行为。发布包层面的测试也增加了,现在会同时从 ESM 和 CommonJS 的 TypeScript 消费者角度检查已发布包的表现。这些改动在代码片段里不好展示,但对一个小库来说很重要------奇怪的 JavaScript 和 TypeScript 环境才是真实世界的考验。
作者自己的使用方式也在变。在 changelog 工具等其它开源项目里,他开始自然地用 is-kit 保持小谓词可复用、可组合,而不是把每个运行时检查都做成孤立辅助函数。他说现在不再想"这里应该用我的库",而是直接拿需要的守卫来用。一个库对维护者开始有用,往往就是从它不再像自己的演示品开始的。

最近一次有意思的反馈来自一个真实使用场景。有人把 is-kit 的守卫用在 Effect 的 filter 里,精炼逻辑本身很普通,但 Effect 的错误通道被意外拓宽成了 unknown。原因是精炼函数的输入类型参与泛型推断,重新定义了 Effect 已经确定的错误类型。相关修复已经合并进 Effect,思路是只让 Effect 的 Error 槽影响类型,不让精炼的输入类型覆盖它,同时为 Channel、Effect、Stream 补了类型测试。is-kit 没有"弄坏 Effect",那个精炼的输入类型本来就有意放宽,问题出在两个泛型 API 相遇时的微妙推断。这种边缘情况很难靠单独测试发现。
100 星仍然不算大项目。星数不是基准,不是正确性证明,也不意味着每个 TypeScript 项目都该安装它。但和 50 星时相比,事情确实不一样了:有人使用、提问、找边缘情况、报 bug、把它和其他校验方案比较、拿它的守卫配合别的库,也有人让作者重新考虑本以为已经完成的 API。这些比数字更有价值。
项目定位也变得更清楚。is-kit 不打算取代 schema 库,不打算把所有运行时值都塞进 schema-first 流程,也不打算隐藏正常的 TypeScript 控制流。它要回答的问题很小:这个值能否安全地进入这个分支?如果需要丰富的校验错误、数据变换、表单验证或跨系统共享的契约,Zod、Valibot 之类的工具更合适。但如果已经有普通的 TypeScript 代码,只缺一个可复用的收窄函数,那就是 is-kit 想待的位置。小型的运行时判断,普通的函数,普通的 TypeScript。

对想尝试的人来说,实用的判断标准是:你是否在重复写零散的运行时检查,是否希望这些检查能组合并保留收窄,是否不想为此引入完整的 schema 工作流。如果答案偏向肯定,它值得一看;如果主要需求是复杂校验和错误信息,先看成熟的 schema 库。