TypeScript实现对象泛型属性分离及类型报错解决
需求说明
实现对象拆分功能:从单个大对象中拆分生成两个对象,按属性是否属于指定泛型类型的定义范围做区分。
示例源对象:
{ name: "John", enabled: false, lastName: "Doe", age: 33 }
指定泛型类型定义:
type User = { name: string; lastName: string; age: number }
函数预期返回元组格式为[不属于该类型的属性对象, 属于该类型的属性对象],对应上述示例的预期返回结果:
[ { enabled: false }, { name: "John", lastName: "Doe", age: 33 } ]
原有实现问题
原有实现代码如下,运行时触发类型报错:
type GenericType<T> = Partial<T> & { [record: string]: unknown } // Values are known properites of T const sortProperties = <T>(values: string[], orginalObject: GenericType<T>){ const validPropertieis: Partial<T> = {}; const inValidProperties: Record<string, unknown> = {}; Object.keys(orginalObject).forEach((key) => { if(values.includes(key){ // No index signature with parameter type 'string' was found on type Partial<T> validPropertieis[key] = values[key]; } else { inValidProperties[key] = values[key]; } return [inValidProperties, validProperties]; }
报错信息:Partial
除了类型报错外,原代码还存在几处逻辑笔误:
- 属性名拼写错误:
validPropertieis、orginalObject拼写有误 if(values.includes(key)语句缺少闭合右括号- 取值逻辑错误:拆分属性时错误从传入的
values数组取值,实际应该从源对象上取对应键的值 - 逻辑错误:
return语句写在了forEach循环内部,会导致遍历第一个属性后就直接终止函数
修正后实现
报错核心原因是TypeScript中Object.keys()默认返回string[]类型,无法直接证明遍历出的字符串属于泛型T的合法键,同时Partial<T>类型默认没有开放字符串索引签名,直接用字符串键赋值会触发类型校验。
修正后的完整可运行代码:
// 定义入参对象类型:兼容泛型T的结构,同时支持任意额外自定义属性 type GenericObject<T> = Partial<T> & Record<string, unknown>; const sortProperties = <T extends object>( targetKeys: Array<keyof T>, sourceObj: GenericObject<T> ): [Record<string, unknown>, Partial<T>] => { const validProperties: Partial<T> = {}; const invalidProperties: Record<string, unknown> = {}; Object.keys(sourceObj).forEach((key) => { const sourceValue = sourceObj[key]; if (targetKeys.includes(key as keyof T)) { // 临时做类型断言绕开索引签名校验,不破坏最终返回的类型安全 (validProperties as Record<string, unknown>)[key] = sourceValue; } else { invalidProperties[key] = sourceValue; } }); return [invalidProperties, validProperties]; }; // 用法示例 type User = { name: string; lastName: string; age: number; }; const sourceData = { name: "John", enabled: false, lastName: "Doe", age: 33 }; const [nonUserFields, userFields] = sortProperties<User>( ["name", "lastName", "age"], sourceData );
修正点说明:
- 修复所有原有笔误,调整return位置到遍历结束后,保证所有属性都能被遍历判断
- 优化入参类型:将属性列表参数从
string[]改为Array<keyof T>,从类型层面约束传入的属性名必须是泛型T的合法键,避免传入无效属性名 - 对赋值时的
validProperties做临时类型断言解决索引签名报错,不改变最终返回值的Partial<T>类型定义 - 明确函数返回值为元组类型,和预期返回结构对齐,调用时可以直接拿到结构正确的两个拆分对象
内容的提问来源于stack exchange,提问作者ForgedFire
相关产品推荐
相关产品推荐

