TypeScript定义二选一字段类型后作为参数访问属性报错如何解决?
问题原因
你当前定义的WithId<T>生成的是交叉后的联合类型,id属性仅存在于联合的第一个分支,oldId仅存在于联合的第二个分支。TypeScript 规则限制:仅允许直接访问联合类型所有分支共有的属性,因此直接访问id会触发不存在的报错。
另外你当前的初始定义还存在一个缺陷:没有禁止id和oldId同时存在的场景,不符合你的业务要求。
解决方案
方案1:先做类型缩小再访问(推荐,保留完整类型校验)
通过in运算符判断当前参数存在哪个属性,TypeScript 会自动缩窄对应分支的类型,访问对应属性就不会报错:
export const someTest = (product: Product) => { if ('id' in product) { // 此分支自动推断product为 {id:string, name:string} 类型 return product.id } // 此分支自动推断product为 {oldId:number, name:string} 类型 return product.oldId }
方案2:调整互斥类型定义,支持可选链直接访问
修改WithId的定义,给互斥字段添加never类型标记,既实现了两个字段严格互斥的要求,也支持用可选链直接访问属性:
// 调整后的类型定义,两个字段严格互斥不可共存 export type WithId<T> = T & ( { id: string; oldId?: never } | { oldId: number; id?: never } )
修改后可直接用可选链或空值合并运算符访问:
export const someTest = (product: Product) => { return product.id ?? product.oldId }
同时如果出现同时传入id和oldId的错误写法,TypeScript 会直接抛出校验错误,更符合你的需求。
方案3:类型断言(不推荐,会跳过类型校验)
如果确定当前场景下参数一定存在id,可以用类型断言强制指定类型,但会失去 TS 的类型校验能力,不建议常规场景使用:
export const someTest = (product: Product) => { return (product as { id: string }).id }
内容的提问来源于stack exchange,提问作者Xero
相关产品推荐
相关产品推荐

