TypeScript递归属性路径拼接无法生成预期联合类型求助
问题原因与解决办法:TypeScript双层嵌套对象路径联合类型返回never
问题原因
你的FirstIteration类型逻辑存在核心问题:当你使用Obj[keyof Obj]时,得到的是所有子对象类型的联合类型(比如typeof ONE_SIMPLE | typeof TWO_SIMPLE | typeof HELLO_SIMPLE | typeof FALSE_SIMPLE)。而keyof作用在联合类型上时,只有当所有成员类型都拥有完全相同的键时,才会返回这些共同键;如果成员键不重合,keyof会直接返回never。这里每个子对象的键都不重复,导致SecondIteration接收的keyof Obj[keyof Obj]是never,最终整个FirstIteration返回never。
解决办法
要解决这个问题,需要使用分布式条件类型,遍历根对象的每个键,单独处理每个键对应的子对象,再拼接路径。修改FirstIteration的定义即可:
interface UnknownRecord { [key: string]: unknown; } type SecondIteration<Prefix extends string, Obj extends UnknownRecord> = keyof Obj extends string ? `${Prefix}.${keyof Obj}` : never; interface DoubleUnknown { [name: string]: UnknownRecord; } // 修改后的FirstIteration:通过分布式条件类型逐个处理每个根键 type FirstIteration<Obj extends DoubleUnknown> = keyof Obj extends infer K ? K extends string ? SecondIteration<K, Obj[K]> : never : never; // 测试代码 const ONE_SIMPLE: { nr1a: number; nr2b: number; } = { nr1a: 1, nr2b: 1 }; const TWO_SIMPLE: { nr2a: number; nr2b: number; } = { nr2a: 2, nr2b: 2 }; const HELLO_SIMPLE: { str1: string } = { str1: 'hello' }; const FALSE_SIMPLE: { bln: boolean } = { bln: false }; const inputs = { ONE_SIMPLE, TWO_SIMPLE, HELLO_SIMPLE, FALSE_SIMPLE }; const firstExample: SecondIteration<'test', typeof ONE_SIMPLE> = 'test.nr2b'; // 现在类型会正确推导为所有合法路径的联合类型 const secondExample: FirstIteration<typeof inputs> = 'ONE_SIMPLE.nr1a';
原理说明
分布式条件类型会自动将联合类型K(即keyof Obj的所有键)拆分为单个成员,对每个K单独执行SecondIteration<K, Obj[K]>,最后将所有结果合并为一个联合类型。这样就避免了直接处理子对象联合类型的问题,确保每个子对象的键都能被正确提取并拼接路径。
内容的提问来源于stack exchange,提问作者Feirell
相关产品推荐
相关产品推荐

