TypeScript类型合并未覆盖属性?求解析怪异推断逻辑
为什么交叉类型不会覆盖activities的类型?
TypeScript的交叉类型(&)对对象同名属性的处理逻辑是取类型交集,而非直接覆盖。
在你的代码中:
type Activity = { a: number }; type Options = { activities: Activity[] } const fun = (options: Options & { activities: Array<{ b: number }> }) => { return options.activities.map(item => item.b) }
Options & { activities: Array<{ b: number }> }这个交叉类型中,activities的实际类型是Activity[] & { b: number }[],等价于(Activity & { b: number })[]——也就是说,activities数组的每个元素必须同时满足{ a: number }和{ b: number }两个类型。
你看到item被推断为{ a: number },本质是TypeScript在类型检查时优先提示基础类型的属性,但实际上item的类型是两者的交集。如果尝试传入仅包含b属性的数组元素,TypeScript会直接报错,因为不满足Activity[]的要求。
为什么Omit<>能解决问题?
Omit<Options, 'activities'>的作用是移除Options类型中指定的activities属性,之后再与{ activities: Array<{ b: number }> }交叉,就不会出现同名属性的类型交集问题。
替换后的类型Omit<Options, 'activities'> & { activities: Array<{ b: number }> },本质是一个全新的对象类型:它保留了Options中除activities外的所有属性,同时将activities的类型完全替换为{ b: number }[],这就符合你原本期望的“覆盖”效果。
两种写法的差异对比
- 交叉类型写法:要求传入的
activities数组元素必须同时拥有a和b属性,否则类型不兼容。 Omit写法:仅要求activities数组元素拥有b属性即可,不需要包含a。
内容的提问来源于stack exchange,提问作者sgmonda

