TypeScript联合类型导致记录值提取异常的技术问询
TypeScript联合类型参数下的Type类型取值错误修复
问题背景
现有以下TypeScript类型定义,用于根据传入的配置记录All和可选参数Part提取各属性取值:若Part指定了对应key的值则取该值,否则取元组中的默认值。
type BuildPart<T extends Record<string, [string, string]>> = '' | { [K in keyof T]: K extends string ? `${K & string}:${T[K][number]}` : never }[keyof T] type Type<All extends Record<string, [string, string]>, Part extends BuildPart<All> = ''> = { [K in keyof All]: K extends string ? Part extends `${K}:${infer V}` ? V : All[K][1] : never }[keyof All]
测试场景中,Part为空或单个值时功能正常,但Part为联合类型时结果不符合预期:
type test0 = Type<{a: ['b' | 'c', 'c'], b: ['d' | 'e', 'd']}> // 'c' | 'd'(符合预期) type test1 = Type<{a: ['b' | 'c', 'c'], b: ['d' | 'e', 'd']}, 'a:b'> // 'b' | 'd'(符合预期) type test2 = Type<{a: ['b' | 'c', 'c'], b: ['d' | 'e', 'd']}, 'a:b' | 'b:e'> // 实际得'b' | 'c' | 'd' | 'e',预期为'b' | 'e'
问题原因
原类型中的Part extends ${K}:${infer V}``属于分布式条件类型:当Part是联合类型时,TypeScript会自动遍历联合中的每个成员单独进行条件判断,再将结果合并。
以test2为例:
- 针对
K='a',Part的两个成员'a:b'和'b:e'会分别判断:'a:b'匹配规则得到V='b','b:e'不匹配则取默认值'c',最终K='a'的结果是'b' | 'c'。 - 针对
K='b',同理会得到'd' | 'e'。 - 合并后出现所有可能值,与预期不符。
解决方案
避免分布式条件类型的影响,改为对整个Part联合判断是否存在当前K对应的条目。用Extract<Part, ${K}:${string}>提取Part中属于当前K的部分,再进行值推断。
修正后的类型定义:
type BuildPart<T extends Record<string, [string, string]>> = '' | { [K in keyof T]: K extends string ? `${K & string}:${T[K][number]}` : never }[keyof T] type Type<All extends Record<string, [string, string]>, Part extends BuildPart<All> = ''> = { [K in keyof All]: K extends string ? Extract<Part, `${K}:${string}`> extends `${K}:${infer V}` ? V : All[K][1] : never }[keyof All]
测试验证
修正后重新测试,结果符合预期:
type test0 = Type<{a: ['b' | 'c', 'c'], b: ['d' | 'e', 'd']}> // 'c' | 'd'(符合预期) type test1 = Type<{a: ['b' | 'c', 'c'], b: ['d' | 'e', 'd']}, 'a:b'> // 'b' | 'd'(符合预期) type test2 = Type<{a: ['b' | 'c', 'c'], b: ['d' | 'e', 'd']}, 'a:b' | 'b:e'> // 'b' | 'e'(符合预期)
原理说明
Extract<Part,${K}:${string}>会从Part联合中筛选出所有符合${K}:xxx格式的条目,若不存在则返回never。- 针对筛选结果推断:如果有匹配条目,就提取对应的
V;否则取默认值。这样每个K只会得到指定值或默认值,不会产生多余的联合分支。
内容的提问来源于stack exchange,提问作者zedryas
相关产品推荐
相关产品推荐

