TypeScript高级类型:如何提取嵌套对象中所有id字段的值?
问题原因分析
你的NestedId类型失效的核心问题在于联合类型的键处理逻辑错误,以及递归范围的局限性:
- 联合类型的
keyof取交集导致递归中断
当处理children数组的元素时,ObjectType[Key][number]是三个对象的联合类型:{ id: "two" } | { id: "three"; children: [...] } | { abc: "def" }。TypeScript中keyof (A | B | C)会返回所有成员键的交集,而这三个对象没有公共键,因此keyof结果为never,映射类型{[Key in ...]: ...}为空,最终递归调用返回never,嵌套的id值完全丢失。 - 递归仅针对
children键,逻辑覆盖不全
原实现只对children键做递归处理,没有考虑对象其他键下可能的嵌套结构,且没有利用TypeScript的分布式条件类型来自动拆分联合类型并逐个处理。
解决方法
可以通过两种方式修复,一种是针对你的原逻辑调整,另一种是实现更通用的全层级id提取类型:
方式一:修复原逻辑(适配children结构)
修改递归逻辑,让联合类型能被正确拆分处理,利用分布式条件类型对每个数组元素单独递归:
type ExampleType = { id: "one" children: [{ id: "two" }, { id: "three"; children: [{ id: "four" }] }, { abc: "def" }] efg: "hij" } // 先处理联合类型的分发,用裸类型参数触发分布式条件类型 type NestedId<T> = T extends Record<string, any> | undefined ? { [Key in keyof T & string]: T[Key] extends undefined ? never : Key extends "id" ? T[Key] : Key extends "children" ? T[Key] extends Array<infer U> ? NestedId<U> // 对数组元素类型单独递归,触发联合分发 : never : never }[keyof T & string] : never const id1: NestedId<ExampleType> = "one" // 正常 const id2: NestedId<ExampleType> = "two" // 正常 const id3: NestedId<ExampleType> = "three" // 正常 const id4: NestedId<ExampleType> = "four" // 正常 const foo: NestedId<ExampleType> = "foo" // 报错(符合预期) const bar: NestedId<ExampleType> = "bar" // 报错(符合预期)
方式二:通用全层级id提取类型(推荐)
如果需要提取任意嵌套结构(不仅限于children数组)中的所有id值,可以实现更通用的类型,自动遍历所有嵌套层级:
type ExampleType = { id: "one" children: [{ id: "two" }, { id: "three"; children: [{ id: "four" }] }, { abc: "def" }] efg: "hij" } type NestedId<T> = // 过滤空值类型 T extends undefined | null ? never : // 提取当前对象的id(如果存在),并递归处理所有值 T extends { id: infer Id } ? Id | NestedId<Exclude<T[keyof T], undefined | null>> : // 处理数组,递归处理元素类型 T extends Array<infer U> ? NestedId<U> : // 处理其他对象,递归处理所有值 T extends object ? NestedId<Exclude<T[keyof T], undefined | null>> : // 非对象/数组类型返回never never const id1: NestedId<ExampleType> = "one" // 正常 const id2: NestedId<ExampleType> = "two" // 正常 const id3: NestedId<ExampleType> = "three" // 正常 const id4: NestedId<ExampleType> = "four" // 正常 const foo: NestedId<ExampleType> = "foo" // 报错(符合预期) const bar: NestedId<ExampleType> = "bar" // 报错(符合预期)
这个通用版本通过分布式条件类型自动拆分联合类型,遍历所有嵌套对象和数组,提取所有层级的id值,适用性更广。
内容的提问来源于stack exchange,提问作者David Alvarez
相关产品推荐
相关产品推荐

