5700星的TypeScript类型工具库,号称类型系统的lodash
5700星的TypeScript类型工具库,号称类型系统的lodash
写TypeScript的人大概都有这个经历:内置的Partial只处理对象第一层,嵌套结构得自己写递归条件类型;想按属性值的类型来筛选字段,Pick按的是键名,帮不上忙;想给number加个"美元"标记让它不能跟普通number混用,得用 branded type 那一套。这些需求单个都不复杂,但每个项目都要重写一次。
piotrwitek/utility-types 就是专门填这些坑的,5.7k Star。作者把它的定位说得很直白:“静态类型版的lodash”,提供TypeScript内置映射类型之外的那些常用类型运算,不用再跨项目复制粘贴类型定义。

核心能力:五大类,约50个工具类型
整个库覆盖了五个方向,按场景挑几个有代表性的说。
Deep系列,嵌套结构一句搞定。 DeepPartial、DeepRequired、DeepReadonly、DeepNonNullable。以往要把一个三层嵌套的配置对象全部标为可选,得写递归条件类型加映射类型。有了DeepPartial<T>,一行类型别名就完事。
按值类型Pick/Omit。 PickByValue和OmitByValue系列不看键名看值类型。例如从一个混杂了string、number、boolean的对象类型中只提出值为number的属性,但内置Pick按的是键的联合类型,做不到这种按值筛选。
集合运算,把数学概念搬进类型系统。 SetIntersection、SetDifference、SetComplement、SymmetricDifference。联合类型之间的交差补运算从此有现成语义,不再靠大脑推导。
Brand,弥补TS结构类型的短板。 TypeScript本质是结构类型系统,两个字段完全相同的类型能互相赋值。Brand<T, U>通过编译期标记制造名义类型差异。把number分别标为USD和EUR后,编译器会拒绝互相赋值,金融计算里这一手能拦住低级类型错误。
Flow兼容层,降低迁移成本。 提供$Keys、$Values、$Diff、$Call、$Shape等一套与Flow Utility Types同名的类型别名。从Flow往TypeScript迁的项目,改个import来源就能复用原有的类型逻辑。
还有其他几类:FunctionKeys和NonFunctionKeys区分方法属性和数据属性;MutableKeys和ReadonlyKeys提取可变/只读键名;Overwrite和Assign实现对象类型的覆盖与合并;UnionToIntersection把联合类型反转为交叉类型;Unionize把对象拆成单属性联合类型。

三个值得提的工程细节
纯类型,零运行时痕迹。 所有工具都是类型层面的运算,编译产物里没有这个库的任何JavaScript代码。npm install只是获取.d.ts定义文件,不增加打包体积。
零第三方依赖。 package.json里dependencies字段是空的。
类型正确性自动化验证。 作者用dts-jest为每个工具类型写了类型级别的单元测试。不是"我觉得类型推导结果没问题"就发布,而是每个类型的运算输出都经过了自动化断言。
仓库文档对每个类型标注了是否TypeScript内置(built-in),五十多个类型哪些是新增的、哪些是内置的,查表即知。TypeScript 3.1以上版本都能用。
适合谁
TypeScript项目规模上去后,类型定义的复杂度跟着涨。只依赖Partial、Pick、Omit、Record这些内置工具,很多场景会陷入手写递归类型的重复劳动。utility-types不太可能成为每个项目的依赖,但它封装的那套类型运算,特别是DeepPartial和Brand,属于用过就不太想回去自己写的范畴。
从Flow迁移过来的项目收益更直接:$Diff、$Keys这类熟悉的API不用从头实现。
过来的项目收益更直接:$Diff、$Keys这类熟悉的API不用从头实现。
更多推荐
所有评论(0)