TypeScript两种交叉类型展开方法的技术差异与输出对比
TypeScript 交叉类型展开:
Expand vs Compute 这里的"解析"指将{ a: string } & { b: string }这类对象交叉类型转换为扁平化的{ a: string, b: string }结构。
1. @jcalz 的 Expand 类型
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
实现原理
通过条件类型推断将类型T复制到新类型变量O中,再通过恒等映射遍历并复制O的所有属性。条件类型推断本身是无操作,但它有两个关键作用:
- 触发联合类型的分发特性
- 强制编译器计算条件的"true"分支(如果去掉推断直接写
{ [K in keyof T]: T[K] },编译器有时只会保留映射类型的原始形式,不会展开交叉类型)
2. Gabriel Vergnaud 的 Compute 类型
/** * Compute is a helper converting intersections of objects into * flat, plain object types. */ type Compute<T> = { [K in keyof T]: T[K] } & unknown
实现原理
先通过映射类型遍历T的属性,再与unknown进行交叉操作。unknown是TypeScript的顶级类型,与任何类型交叉都不会改变原类型,但这个操作会触发编译器对交叉类型进行扁平化计算。
两者的技术差异与适用场景
输出差异场景
- 联合类型处理:
Expand因为使用了条件类型推断,会对联合类型进行分发。比如Expand<{a: string} | {b: number}>会被处理为{a: string} | {b: number}(每个联合成员都被展开);而Compute不会分发联合类型,Compute<{a: string} | {b: number}>会直接返回等价于原联合类型的结果,但不会对每个成员单独展开。 - 嵌套交叉类型:对于深层嵌套的交叉类型,两者都能展开,但
Expand的推断机制在某些复杂嵌套场景下可能更稳定地触发展开;Compute的交叉unknown方式在极端嵌套情况下可能需要多次调用才能完全展开,不过大多数常规场景下两者效果一致。
性能对比
Expand:由于涉及条件类型推断和联合分发,在处理大规模联合类型或复杂嵌套类型时,可能会带来额外的类型计算开销,编译器需要逐个处理联合成员,性能略逊于Compute。Compute:实现更简洁,仅通过映射加交叉unknown触发展开,没有联合分发的额外开销,在大多数场景下性能更优,尤其是处理非联合类型的交叉时。
内容的提问来源于stack exchange,提问作者Darryl Noakes
相关产品推荐
相关产品推荐

