如何将嵌套结构的TypeScript类型扁平化为指定格式?
嵌套Schema类型扁平化实现
要把嵌套的Schema类型转换成带点路径的扁平对象类型,可以通过联合类型转交叉类型结合受控递归解决,同时规避"类型实例化过深"的报错。
完整实现代码
type FSchema = { type: string; fields?: Record<string, FSchema> } // 递归生成所有路径与对应类型的映射 type FlattenSchema<T extends Record<string, FSchema>, Prefix extends string = ""> = { [K in keyof T & string]: `${Prefix}${Prefix extends "" ? "" : "."}${K}` extends infer Path extends string ? { [P in Path]: { type: T[K]["type"] } } & (T[K] extends { fields: infer F extends Record<string, FSchema> } ? FlattenSchema<F, `${Prefix}${Prefix extends "" ? "" : "."}${K}`> : {}) : never }[keyof T & string] // 将联合类型转换为交叉类型 type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never // 最终的扁平化类型 type MyFlattenedSchema = UnionToIntersection<FlattenSchema<MySchema["fields"]>>
代码说明
FlattenSchema 递归生成路径映射
- 遍历输入Schema的每个字段,拼接前缀生成当前字段的完整路径。
- 为每个路径创建单键对象类型
{ [Path]: { type: ... } }。 - 若当前字段包含子
fields,递归处理子字段并通过&合并当前路径与子路径的类型,最终生成多个单键对象的联合类型。
UnionToIntersection 联合转交叉
- 利用TypeScript条件类型特性,把多个单键对象的联合类型合并成一个包含所有路径的扁平对象类型。
规避递归过深报错
- 原实现中
GetPathAndChilds嵌套了多层递归对象,容易触发TypeScript的递归深度限制。新实现直接在字段遍历中处理递归,每一层只生成当前和子路径的联合,再通过交叉合并,大幅降低了类型实例化的复杂度。
- 原实现中
验证结果
对于给定的MySchema:
type MySchema = { fields: { hello: { type: 'Group' fields: { world: { type: 'Group' fields: { yay: { type: 'Boolean' } } } } } world: { type: 'Boolean' } } }
MyFlattenedSchema会正确解析为:
{ hello: { type: 'Group' } 'hello.world': { type: 'Group' } 'hello.world.yay': { type: 'Boolean' } world: { type: 'Boolean' } }
内容的提问来源于stack exchange,提问作者smsh
相关产品推荐
相关产品推荐

