如何将TypeScript交叉类型的所有字段合并为单个对象类型?
如何在TypeScript中实现可展开的交叉类型合并工具?
在TypeScript中定义交叉类型(如type All = A & B & C & D)时,类型会显示为多个对象的交叉形式,可读性很差,排查TS错误时尤其麻烦。我自己写了个Merge泛型工具,但结果总是嵌套的Merge调用,没法直接展开成包含所有字段的单个对象类型。比如希望Merge<A,B>能直接生成{ foo: string; fizz: number },请问该怎么实现?
示例代码:
type A = { foo: string } type B = { fizz: number } type C = { bar: boolean } type D = { buzz: null | string } type All = A & B & C & D
尝试的Merge泛型:
type Merge<T, U> = { [P in (keyof T | keyof U)]: P extends keyof T ? T[P] : P extends keyof U ? U[P] : never; }
解决方案
要实现能直接展开为单个对象的合并工具,需要处理递归合并逻辑,同时触发TypeScript自动展开最终的类型结构,具体实现如下:
1. 二元类型合并(支持自动展开)
先优化二元合并逻辑,确保合并后的类型不会以交叉形式显示:
// 先处理键覆盖,再通过映射类型触发展开 type MergeTwo<T, U> = Omit<T, keyof U> & U; type Merge<T, U> = { [K in keyof MergeTwo<T, U>]: MergeTwo<T, U>[K] };
2. 支持多类型合并的递归泛型
如果需要合并任意数量的类型,可以写一个递归工具遍历类型数组:
type MergeAll<T extends any[]> = T extends [infer First, ...infer Rest] ? Merge<First, MergeAll<Rest>> : {};
3. 使用示例
type A = { foo: string } type B = { fizz: number } type C = { bar: boolean } type D = { buzz: null | string } // 合并两个类型,直接展开为单个对象 type MergedAB = Merge<A, B>; // 类型显示:{ foo: string; fizz: number } // 合并多个类型 type AllMerged = MergeAll<[A, B, C, D]>; // 类型显示:{ foo: string; fizz: number; bar: boolean; buzz: null | string }
原理说明
MergeTwo先通过Omit<T, keyof U> & U处理键的覆盖逻辑(后传入的类型会覆盖前一个类型的同名键),再通过Merge的映射类型重新构造对象,触发TypeScript的类型展开机制,避免显示为交叉类型。MergeAll利用递归遍历类型数组,逐个合并所有传入的类型,最终得到完全展开的单个对象类型。
内容的提问来源于stack exchange,提问作者frankchoongsaeng
相关产品推荐
相关产品推荐

