TypeScript中Extract<keyof R, string>无法索引类型T的错误解决与函数实现
TypeScript泛型合并对象报错:
Type 'Extract<keyof R, string>' cannot be used to index type 'T' 错误代码
function mergeObjects<T extends object, R extends object>(obj1: T, obj2: R): object { const copy: T = { ...obj1 }; for (const key in obj2) { if (!copy.hasOwnProperty(key)) { copy[key] = obj2[key]; // 此处触发类型错误 } } return copy; }
需求
实现mergeObjects泛型函数,接收两个对象,返回包含第一个对象所有属性,以及第二个对象中未在第一个对象出现的属性的新对象。示例:
const user = { name: 'Harry', surname: 'Potter', }; const robot = { name: 'Cleaner', version: 12, wheels: 3, }; // 期望返回结果 mergeObjects(user, robot) === { name: 'Harry', surname: 'Potter', version: 12, wheels: 3, }
问题原因
TypeScript类型系统无法通过hasOwnProperty的运行时判断,推导出key一定不属于T的键集合,因此认为key不能安全地用来索引T类型的变量copy。
修复方案
方案1:类型断言+精确返回类型
通过类型断言告诉TypeScriptkey是copy的合法键,同时指定函数返回类型为T & Omit<R, keyof T>(即T的所有属性加上R中不在T内的属性):
function mergeObjects<T extends object, R extends object>(obj1: T, obj2: R): T & Omit<R, keyof T> { const copy = { ...obj1 } as T & Omit<R, keyof T>; for (const key in obj2) { if (!copy.hasOwnProperty(key)) { copy[key as keyof typeof copy] = obj2[key]; } } return copy; }
方案2:对象展开语法简化实现
利用对象展开的特性(后展开的对象属性会覆盖先展开的),直接一行代码实现,类型推导更简洁:
function mergeObjects<T extends object, R extends object>(obj1: T, obj2: R): T & Omit<R, keyof T> { return { ...obj2, ...obj1 }; }
这里将obj1放在后面展开,会覆盖obj2中重复的属性,正好满足保留第一个对象属性、合并第二个对象独有属性的需求。
内容的提问来源于stack exchange,提问作者m.strilec
相关产品推荐
相关产品推荐

