扁平化复杂Record时移除冗余交叉类型的技术问题
解决TypeScript Flattened类型中重复交叉类型的问题
问题描述
实现的Flattened类型在处理包含孤立键(如示例中的d)且该键值为联合类型的Record时,会生成大量重复的交叉类型项。比如输入:
{ a: { b: ComplexA }; c: { d: ComplexB }; d: ComplexB; }
期望生成的类型是:
{ a_b: ComplexA } & { c_d: ComplexB } & { d: ComplexB }
但实际生成的类型中,{ d: ComplexB }会重复出现多次(次数等于联合类型的成员数)。
问题原因
原代码中,处理孤立键的联合类型值时,{ [K in keyof T & string]: ... }[keyof T & string]会触发TypeScript的联合类型分发机制,对联合类型的每个成员单独生成一个{ d: 联合成员 }类型,之后UnionToIntersection将这些类型交叉合并,最终形成重复的{ d: ComplexB }项(虽然{d: B1} & {d: B2} & {d: B3}等价于{d: B1|B2|B3},但类型显示上会保留所有交叉项)。
修复后的代码
type Primitive = number | string | boolean | Date; export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; export type Flattened<T, Sep extends string> = T extends | Primitive | unknown[] | Record<string, Primitive | unknown[]> ? T : T extends Record<string, unknown> ? UnionToIntersection< { [K in keyof T & string]: type Flat = Flattened<T[K], Sep>; Flat extends Primitive | unknown[] ? { [P in K]: T[P] } : Flat extends Record<string, unknown> ? { [KFlat in keyof Flat & string as `${K}${Sep}${KFlat}`]: Flat[KFlat]; } : { [KFlat in K]: Flat } }[keyof T & string] > : T; type ComplexA = "complexA1" | "complexA2"; type ComplexB = "complexB1" | "complexB2" | "complexB3"; // 现在生成的类型符合预期:{a_b: ComplexA} & {c_d: ComplexB} & {d: ComplexB} type Result = Flattened< { a: { b: ComplexA }; c: { d: ComplexB }; d: ComplexB; }, '_' >
修复说明
核心修改点:
- 将原代码中
Flattened<T[K], Sep> extends infer Flat的条件推断改为直接声明type Flat = Flattened<T[K], Sep>,避免在条件判断中触发联合类型分发 - 对于非Primitive/数组/Record的情况(即联合类型),直接生成包含整个联合类型的
{ [KFlat in K]: Flat },不再对每个联合成员单独生成类型
这样就避免了联合类型分发导致的重复交叉项,生成的类型结构更简洁且符合预期。
内容的提问来源于stack exchange,提问作者Flavian Hautbois
相关产品推荐
相关产品推荐

