求助:将JavaScript对象扁平化函数转换为TypeScript(参数类型困惑)
解决对象扁平化函数的TypeScript类型定义问题
首先修正原代码里的一个逻辑问题:contact: +91-999999999会被JavaScript解析为数值计算式(结果为-999999908),应该改成字符串形式contact: "+91-999999999"来保留正确的联系方式格式。
以下是完整的TypeScript改造方案:
1. 定义递归扁平化类型
我们需要一个泛型类型来描述扁平化后的对象结构,它会递归地将嵌套对象的键用.拼接:
type FlattenedObject<T> = T extends object ? { [K in keyof T as T[K] extends object ? `${Exclude<K, symbol>}.${keyof FlattenedObject<T[K]> & string}` : Exclude<K, symbol>]: T[K] extends object ? FlattenedObject<T[K]>[keyof FlattenedObject<T[K]>] : T[K] } : T;
这个类型的作用:
- 若
T是对象类型,遍历所有键K - 若
T[K]也是对象,将K与T[K]扁平化后的键拼接为K.subKey格式 - 最终生成所有键为扁平路径、值为原嵌套值的类型
2. 改造扁平化函数
给函数添加泛型参数,指定参数和返回值类型,同时优化遍历逻辑避免原型链污染:
// 定义原始对象的类型 type OriginalObject = { Company: string; Address: string; contact: string; mentor: { HTML: string; CSS: string; JavaScript: string; }; }; // 声明对象并指定类型 const ob: OriginalObject = { Company: "GeeksforGeeks", Address: "Noida", contact: "+91-999999999", mentor: { HTML: "GFG", CSS: "GFG", JavaScript: "GFG" } }; // 带类型约束的扁平化函数 const flattenObj = <T extends object>(ob: T): FlattenedObject<T> => { const result = {} as FlattenedObject<T>; for (const i in ob) { // 仅遍历对象自身属性,避免原型链属性干扰 if (Object.prototype.hasOwnProperty.call(ob, i)) { const value = ob[i]; // 判断是否为非数组的对象类型,递归处理 if (typeof value === 'object' && value !== null && !Array.isArray(value)) { const temp = flattenObj(value); for (const j in temp) { if (Object.prototype.hasOwnProperty.call(temp, j)) { result[`${i}.${j}` as keyof FlattenedObject<T>] = temp[j]; } } } else { result[i as keyof FlattenedObject<T>] = value as FlattenedObject<T>[keyof FlattenedObject<T>]; } } } return result; }; // 调用函数,TypeScript会自动推断返回值的完整类型 const flattened = flattenObj(ob); console.log(flattened);
关键细节说明
- 使用
Object.prototype.hasOwnProperty.call过滤原型链属性,提升代码健壮性 - 通过
as进行类型断言,弥补TypeScript对递归扁平化类型的自动推断局限 - 泛型
T extends object确保参数仅接受对象类型,排除原始类型和数组 FlattenedObject<T>会提供完整的类型提示,比如访问flattened["mentor.HTML"]时会有明确的类型校验
输出结果
运行后控制台输出:
{ Company: 'GeeksforGeeks', Address: 'Noida', contact: '+91-999999999', 'mentor.HTML': 'GFG', 'mentor.CSS': 'GFG', 'mentor.JavaScript': 'GFG' }
内容的提问来源于stack exchange,提问作者Malik Lakhani
相关产品推荐
相关产品推荐

