TypeScript:如何将含Nested泛型的嵌套类型平展为父级类型?
如何实现将Nested泛型类型平展并保持键值对应?
给定包含Nested<T>泛型的类型,需要实现FlatNested<T>类型,将Nested<T>内部的内容平展到父类型中,使平展后的类型能正确关联键与对应的值,而非将所有值合并为联合类型。
问题重现
现有代码实现的FlatNested会将嵌套类型的值变为联合类型,无法匹配对应键:
type Nested<T> = T & { _: string } // 确保Nested<T>与T不相等 type Example = { a: string, b: string, n: Nested<{ n1: 'n1-val', n2: 'n2-val' }> } type FlatNested<T> = { [K in keyof T as T[K] extends Nested<infer N> ? keyof N : K]: T[K] extends Nested<infer N> ? T[K][keyof N] : T[K] }; type t1 = FlatNested<Example> // 当前结果:{a: string;b: string;n1: "n1-val" | "n2-val";n2: "n1-val" | "n2-val";} // 期望结果:{a: string;b: string;n1: "n1-val" ;n2: "n2-val";}
问题原因
原实现中,T[K][keyof N]会取N所有值的联合类型——因为keyof N是N所有键的联合,所以每个平展后的键都会拿到所有嵌套值的集合,而非对应键的具体值。
解决方案
将逻辑拆分为两部分:保留非嵌套属性、平展嵌套属性并关联对应键值,最后通过交叉类型合并结果:
type Nested<T> = T & { _: string } type Example = { a: string, b: string, n: Nested<{ n1: 'n1-val', n2: 'n2-val' }> } // 提取并保留所有非Nested类型的属性 type NonNestedProps<T> = { [K in keyof T as T[K] extends Nested<any> ? never : K]: T[K] } // 提取Nested类型内部的属性,并映射到对应的值 type FlattenNestedProps<T> = { [K in keyof T as T[K] extends Nested<infer N> ? keyof N : never]: T[K] extends Nested<infer N> ? N[K] : never } // 合并非嵌套属性与平展后的嵌套属性 type FlatNested<T> = NonNestedProps<T> & FlattenNestedProps<T> // 验证结果 type t1 = FlatNested<Example> // 结果等价于:{a: string; b: string; n1: "n1-val"; n2: "n2-val";}
代码解释
NonNestedProps<T>:遍历T的所有键,过滤掉类型为Nested<any>的属性,保留原本的非嵌套属性。FlattenNestedProps<T>:遍历T的所有键,当遇到Nested<infer N>类型时,将N的键作为新键,并直接取N[K]作为对应值——这里K是N的键,因此能精准关联到对应的值。- 交叉类型
&将两部分属性合并,得到最终的平展类型。
如果需要支持多层嵌套的平展,可以将FlatNested改为递归实现:
type FlatNestedRecursive<T> = T extends Nested<infer N> ? FlatNestedRecursive<N> : { [K in keyof T]: T[K] extends Nested<infer N> ? FlatNestedRecursive<N> : T[K] }
内容的提问来源于stack exchange,提问作者Eliav Louski
相关产品推荐
相关产品推荐

