为何可选对象成员类型被标记为never?TypeScript技术问询
prop(test.two, 'n')会出现类型错误,如何修复? 这个问题我之前也踩过坑,核心是TypeScript对联合类型的keyof处理逻辑导致的,咱们一步步拆解来看:
问题原因
首先看test.two的类型:根据定义的Test接口,two是可选属性,所以它的类型是{ n: number } | undefined。
当你把test.two传给prop函数的第一个参数obj时,TypeScript会把obj的类型推断为{ n: number } | undefined。接下来看泛型约束K extends keyof O,这里的O是{ n: number } | undefined,而keyof ({ n: number } | undefined)其实是never——因为联合类型的keyof取的是所有成员类型的keyof的交集,undefined没有任何可枚举属性,它的keyof是never,两者的交集自然也是never,这就导致'n'无法赋值给never,出现了你看到的错误。
而prop(test, 'one')正常的原因是test的类型是Test,keyof Test是'one' | 'two','one'完全符合K extends keyof O的约束,所以编译没问题。
修复方案
这里有几种不同的修复方式,你可以根据实际场景选择:
方案1:使用非空断言(快速但需确保安全)
如果你能确定test.two在运行时一定存在(比如当前代码逻辑里已经明确赋值过),可以用非空断言!告诉TypeScript这个值不是undefined:
let y = prop(test.two!, 'n') // 编译正常,y类型为number
⚠️ 注意:这种方式如果运行时test.two实际是undefined,会抛出运行时错误,所以只有当你100%确定值存在时才用。
方案2:改进prop函数,兼容可选/可能为undefined的对象
我们可以修改prop函数,让它能处理obj可能为undefined的情况,同时通过条件类型正确推导返回值:
function prop<O, K extends keyof NonNullable<O>>( obj: O, key: K ): O extends NonNullable<O> ? NonNullable<O>[K] : NonNullable<O>[K] | undefined { return obj?.[key] as any }
这个版本的prop用NonNullable<O>获取去掉undefined和null后的类型,让K约束为该类型的key。返回值通过条件类型区分:如果obj本身是非空的,返回对应属性类型;如果可能为空,返回属性类型或undefined。
现在调用prop(test.two, 'n')会正常编译,y的类型是number | undefined,完全符合预期。
方案3:先做类型守卫,确保对象存在再调用
如果不想修改prop函数,可以先通过类型守卫判断test.two是否存在,再调用prop:
if (test.two) { let y = prop(test.two, 'n') // 编译正常,y类型为number }
在if分支里,TypeScript会把test.two的类型自动收窄为{ n: number },此时keyof {n:number}是'n',完全符合泛型约束,不会报错。
内容的提问来源于stack exchange,提问作者Stephan Schreiber

