TypeScript遍历解析对象精简数据时rtn[key]赋值报错
问题背景
开发对象解析逻辑用于剔除冗余嵌套数据时,代码在rtn[key]赋值语句处触发TypeScript类型报错,暂未定位报错原因。
复现代码
type TValueCar = { make: { value: string }; model: { value: string } }; type TCarKey = keyof TValueCar; type TCar = { make: { value: string }; model: { value: string } }; const parseCarValueObject = (valueObject: TValueCar): TCar => { const ObjectKeys = Object.keys(valueObject) as TCarKey[]; const rtn = {} as TCar; ObjectKeys.forEach((key) => { rtn[key] = valueObject[key].value; }); return rtn; };
补充说明(tl;dr)
最终目标是实现该解析函数的泛型版本,当前代码是泛型实现过程中的第一步。已知存在更简单的直接属性赋值实现方案,但该硬编码写法无法支撑通用泛型函数的开发需求,因此不采用:
const rtn = { make: valueObject.make.value, model: valueObject.model.value }
报错原因
报错由两个问题共同导致:
- 类型定义不匹配:定义的
TCar类型和入参TValueCar结构完全一致,属性类型均为{ value: string },但赋值语句右侧取的是valueObject[key].value,类型为string,本身就和rtn[key]的声明类型不匹配。 - 联合类型key的相关性丢失:即使修正
TCar为扁平化结构{ make: string; model: string },TS在遍历"make" | "model"联合类型的key时,会独立判定赋值操作左右两侧的key类型,默认认为存在rtn["make"]被赋值valueObject["model"].value的跨key赋值风险,依然会抛出类型错误。
修复方案
非泛型版本快速修复
先修正TCar的类型定义为扁平化结构,TS即可正常识别赋值逻辑,如遇严格模式校验可补充轻量类型断言:
type TCar = { make: string; model: string }; // 修正类型定义 const parseCarValueObject = (valueObject: TValueCar): TCar => { const ObjectKeys = Object.keys(valueObject) as TCarKey[]; const rtn = {} as TCar; ObjectKeys.forEach((key) => { rtn[key] = valueObject[key].value; }); return rtn; };
通用泛型版本实现
可直接编写通用泛型方法,自动匹配入参结构返回扁平化后的解析结果,无需硬编码属性名,满足通用解析需求:
// 定义通用嵌套value包装类型 type ValueWrapper<T = unknown> = { value: T }; /** * 解析所有属性为{value: xxx}结构的嵌套对象,返回扁平化后的普通对象 */ const parseValueObject = <T extends Record<PropertyKey, ValueWrapper>>(valueObject: T) => { const result = {} as { [K in keyof T]: T[K] extends ValueWrapper<infer V> ? V : never }; (Object.keys(valueObject) as (keyof T)[]).forEach((key) => { result[key] = valueObject[key].value; }); return result; }; // 用法示例:TS会自动推导返回值类型为 { make: string; model: string } const parsedCar = parseValueObject({ make: { value: "Tesla" }, model: { value: "Model 3" } });
内容的提问来源于stack exchange,提问作者moroncodes
相关产品推荐
相关产品推荐

