TypeScript类型转换中如何保留联合类型避免被条件类型分发解构
问题场景
现有如下类型定义:
type Test = { checked: boolean; selection: 'female' | 'male' }
需要将其转换为所有非对象属性值包裹为Record<string, 原属性类型>的结构,目标类型如下:
type Test = { checked: Record<string, boolean>; selection: Record<string, 'female' | 'male'> }
最初编写的泛型转换逻辑如下:
type NestedTest<T> = T extends object ? { [P in keyof T]: NestedTest<T[P]> } : Record<string, T>;
执行type Test2 = NestedTest<Test>;后得到的结果不符合预期,原联合类型被拆分:
type Test2 = { checked: Record<string, false> | Record<string, true>; selection: Record<string, "female"> | Record<string, "male">; }
问题原因
该现象由TypeScript条件类型的分配式特性导致:
- 当条件类型的泛型参数是未被包裹的裸类型参数时,若传入联合类型,TypeScript会将联合类型拆分为单个独立成员,逐个代入条件类型逻辑计算,最终将所有计算结果合并为新的联合类型返回。
- 原代码中
T extends object属于裸类型参数的条件判断:- 传入
boolean(本质是true | false联合类型)时,会分别计算true和false两个分支,最终得到Record<string, true> | Record<string, false> - 传入
'female' | 'male'联合类型时,会分别计算两个字面量类型分支,最终得到Record<string, 'female'> | Record<string, 'male'>
- 传入
修复方案
关闭条件类型的分配特性即可,只需要将条件判断的两侧类型都用元组包裹,阻止TypeScript拆分联合类型:
type NestedTest<T> = [T] extends [object] ? { [P in keyof T]: NestedTest<T[P]> } : Record<string, T>;
使用修改后的泛型转换Test类型,即可得到预期结果:
type Test2 = NestedTest<Test>; // 输出结果: // type Test2 = { // checked: Record<string, boolean>; // selection: Record<string, "female" | "male">; // }
内容的提问来源于stack exchange,提问作者ttquang1063750
相关产品推荐
相关产品推荐

