如何在TypeScript交叉类型中使用infer?嵌套泛型类型转换问题
解决交叉类型中infer无法解析嵌套泛型的问题
问题说明
我在开发一个关联数据查询构建器,核心需求是把嵌套的泛型类型按照嵌套深度转换成对应维度的数组(比如一级嵌套对应T[],二级对应T[][])。
为了让开发者调用Person.select()时,既能使用原类的get/set方法,又能调用filter()这类专属查询方法,我把原Shape类型转换为QueryShape<..> & MappedShape<..>的交叉类型——其中MappedShape负责将原属性转为映射查询对象,QueryShape提供查询方法。
但现在遇到了问题:infer关键字在交叉类型里无法正常工作。像result、result2能正确推导为string[]、string[][],但result3、result4的类型却是unknown,我预期p.friend.friend的类型应该是Person[][]。
解决方案
问题根源在于交叉类型的歧义——TypeScript直接对交叉类型使用infer时,无法明确该从哪一部分提取泛型参数。我们需要先把交叉类型里的MappedShape部分单独提取出来,再进行递归的数组转换。
修改后的类型工具与完整代码
// 定义查询方法的基础类型 type QueryShape<T> = { filter: (predicate: (item: T) => boolean) => void; select: () => NestedArray<QueryShape<T> & MappedShape<T>>; }; // 把原Shape的属性映射为查询对象类型 type MappedShape<T> = { [K in keyof T]: T[K] extends object ? QueryShape<T[K]> & MappedShape<T[K]> : T[K]; }; // 从交叉类型里提取出MappedShape部分 type ExtractMappedShape<T> = T extends QueryShape<infer S> & MappedShape<infer S> ? MappedShape<S> : never; // 递归生成对应嵌套深度的数组类型 type NestedArray<T> = T extends { [K in keyof T]: infer U } ? U extends object ? NestedArray<ExtractMappedShape<U>>[] : U[] : never; // 示例Person类 class Person { name: string; friend: Person; constructor(name: string) { this.name = name; this.friend = this; // 简化示例逻辑 } static select(): NestedArray<QueryShape<Person> & MappedShape<Person>> { return [] as any; } } // 使用验证 const result = Person.select().map(p => p.name); // 类型:string[] const result2 = Person.select().map(p => p.friend.name); // 类型:string[][] const result3 = Person.select().map(p => p.friend); // 类型:Person[][] const result4 = Person.select().map(p => p.friend.friend); // 类型:Person[][][]
原理说明
- 交叉类型的歧义问题:
QueryShape<S> & MappedShape<S>是两种类型的合并结构,直接用infer时,TypeScript无法确定该提取哪部分的泛型参数,只能返回unknown。 - ExtractMappedShape的作用:通过明确匹配交叉类型的结构,单独提取出负责属性映射的
MappedShape部分,避免递归时被QueryShape里的方法干扰,确保能正确拿到嵌套的属性类型。 - 递归数组生成:在
NestedArray类型中,先判断属性是否为对象类型,如果是则先提取其MappedShape部分,再递归生成数组类型,从而实现根据嵌套深度生成对应维度的数组。
内容的提问来源于stack exchange,提问作者Flion
相关产品推荐
相关产品推荐

