You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript 意外行为求解:为何未检测到对象合并类型问题?

TypeScript未检测到对象展开覆盖问题的原因解析

问题现象

将两个对象通过Object.values转为数组后展开合并为新对象时,object1的前四个值会被object2的对应索引值覆盖,合并后的mergedObjects中实际不存在这些被覆盖的值,但TypeScript却允许将这些被覆盖的值传入tryThis函数;而传入完全不属于两个对象的取值时,TS会正常报错。

示例代码

const object1 = {
    one: 'hey brother',
    two: 'hi bro',
    three: 'how are you?',
    four: 'good thanks',
    five: 'Great',
    six: 'bye'
} as const

const object2 = { 
    one: 'wrong',
    two: 'falsch',
    three: 'right',
    four: 'recht'
} as const

const mergedObjects = {
    ...Object.values(object1),
    ...Object.values(object2)
} as const

type MergedObjectValue = (typeof mergedObjects)[number]

const tryThis = (value: MergedObjectValue) => {
    // do nada
}

console.log("mergedObjects", mergedObjects)

// TS 不报错,但值实际不在 mergedObjects 中
tryThis('hey brother') 
// TS 不报错,值存在于 mergedObjects 中
tryThis('wrong') 

// TS 报错,值完全不存在
tryThis('this is not in either')

问题根源

TypeScript的类型系统是静态分析机制,不会模拟运行时的执行逻辑,具体原因可拆解为以下几点:

  • Object.values的类型推导:因为使用了as const断言,Object.values(object1)会被推导为包含所有值的只读数组类型readonly ["hey brother", "hi bro", ..., "bye"],Object.values(object2)同理,类型是固定的集合。

  • 数组展开到对象的类型合并规则:当把数组展开到对象中时,TS会直接合并两个数组的所有值的联合类型,作为对象值的类型。它不会考虑“后面数组的同索引键会覆盖前面数组”这个运行时行为,只会认为合并后的对象的取值是两个数组所有值的集合。

  • 索引签名的类型生成:最终mergedObjects的类型被推导为带有数字索引的对象,索引对应的类型是两个数组值的完整联合类型。所以MergedObjectValue就是这个联合类型,自然允许传入被覆盖的'hey brother'这类值,而完全不在联合里的字符串会被TS拦截。

简单来说:TS只关注你合并了哪些值的类型,不会追踪这些值在运行时会不会被覆盖。

内容的提问来源于stack exchange,提问作者Alfie Freeman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:23:32