TypeScript中Object.assign结合Omit类型使用不符合预期如何解决
报错原因
你认为Omit<U, keyof T> & T等价于U的逻辑在属性类型完全一致的场景下是成立的,但TypeScript的类型系统不认可这个等价关系,核心原因是U extends T只约束U必须包含T的所有属性,没有约束U中与T同名属性的类型必须和T完全一致:U的同名属性可以是T对应属性的子类型。
举个实际的反例:
type T = { id: string | number, name: string } // U满足U extends T,但id和name的类型都比T更窄 type U = { id: number, name: '静态字符串', age: number }
这种场景下Omit<U, keyof T>得到的是{age: number},和T交叉之后得到的类型是{id: string | number, name: string, age: number},和U的类型并不等价,所以TypeScript会抛出错误。
无类型断言的解决方案
只要调整泛型定义,把U拆成「T + 额外属性」的显式交叉结构,就能让TypeScript识别到合并后的类型符合要求:
export const mergeArray = <T, Extra extends object>(params: { mergeInArray: Array<T> existingArray: Array<T & Extra> matchKey: keyof T fallbackValues: Extra }): Array<T & Extra> => { const { mergeInArray, existingArray, matchKey, fallbackValues, } = params return mergeInArray.map(itemToMergeIn => { const existingItem = existingArray.find( searchItem => searchItem[matchKey] === itemToMergeIn[matchKey] ) if (existingItem) { // 注意:原有写法会修改existingArray中的原对象,不需要副作用的话建议加空对象作为第一个参数 return Object.assign({}, existingItem, itemToMergeIn) } // 同理,避免修改传入的fallbackValues,也加空对象 return Object.assign({}, fallbackValues, itemToMergeIn) }) }
这个写法完全不需要类型断言,TypeScript可以正常推导出返回值类型符合要求,原有功能也完全不变。如果有需要,你也可以给T & Extra声明一个别名U,不影响类型推导逻辑。
内容的提问来源于stack exchange,提问作者fullStackChris
相关产品推荐
相关产品推荐

