TypeScript映射类型中数组类型扁平化转换失败问题
问题:将嵌套对象与数组属性统一转为number类型的映射类型错误
原始接口定义
interface IUserMongo { name: string; age: number; address: string[]; nested: { name: string; sayYes: boolean; rrr: 1; }; }
期望生成的类型
希望派生一个所有属性(包括嵌套对象属性)类型均为number的类型:
interface IUserMongo { name: number; age: number; address: number; nested: { name: number; sayYes: number; rrr: number; }; }
当前问题
编写的IUserProject映射类型处理嵌套对象正常,但处理数组时触发类型错误:
error: Type 'number' is not assignable to type 'number[]'
完整代码示例
interface IUserMongo { name: string; age: number; address: string[]; nested: { name: string; sayYes: boolean; rrr: 1; }; } type IUserProject<T, N = number> = { [K in keyof T]: T[K] extends object ? IUserProject<T[K], N> : N; }; const projection: IUserProject<IUserMongo> = { name: 1, age: 1, address: 1, // 此处报错 nested: { sayYes: 1, name: 1, rrr: 1, }, }; const user: IUserMongo = { name: 'sdg', age: 1, address: ['gfg'], nested: { sayYes: true, name: 'rrr', rrr: 1, }, }; // 期望的数组处理行为示例 interface MultiContainer { Item1: string[]; Item2: number[]; } type SingleContainer = { [P in keyof MultiContainer]: number }; const tt: SingleContainer = { Item1: 1, Item2: 1, };
问题原因
当前的映射类型中,T[K] extends object会将数组判定为object类型(数组在TypeScript中属于object的子类型),导致代码递归处理数组的元素类型,最终数组属性被映射为number[],但我们需要的是直接将数组属性的类型替换为number。
解决方案
修改映射类型,优先判断属性是否为数组类型,若是则直接返回目标类型N;否则再判断是否为对象并递归处理:
type IUserProject<T, N = number> = { [K in keyof T]: T[K] extends readonly any[] ? N : T[K] extends object ? IUserProject<T[K], N> : N; };
修改后,projection中的address:1不再报错,所有属性类型均符合期望的number类型,包括嵌套对象的属性。
内容的提问来源于stack exchange,提问作者ashen madusanka
相关产品推荐
相关产品推荐

