TypeScript中如何实现Result类型的自动解包与类型收窄,无需额外判断error属性
解决Result联合类型的类型解包问题
你遇到的核心问题是TypeScript无法自动推断出unwrapResult函数抛出错误后,返回的必然是联合类型中无error的成功成员。我们可以通过条件类型配合类型断言,让函数返回类型精确匹配成功结果,这样调用后就能直接访问response属性,无需额外判断。
解决方案代码
首先定义一个辅助类型,用来提取联合类型中error为undefined的成功分支:
type SuccessResult<T> = T extends { error: undefined } ? T : never;
接着修改unwrapResult函数,让它返回这个精确的成功类型:
type Result = {error:true,response: undefined} | {error:undefined, response:{nick:string}} function unwrapResult<T extends { error: any }>(result: T): SuccessResult<T> { if(result.error){ throw result.error } // 类型断言是安全的:运行时已通过if排除了error存在的情况 return result as SuccessResult<T> } function test():Result { return {error:undefined,response:{nick:'iki'}} } // data的类型被正确推断为{error:undefined, response:{nick:string}} const data = unwrapResult(test()) // 可直接访问,无需可选链或额外判断 console.log(data.response.nick) // 类型为string,无undefined提示
原函数失效的原因
你的原函数返回泛型参数T,而T对应Result联合类型。虽然运行时我们抛出错误只返回成功结果,但TypeScript类型系统无法自动从联合类型中排除带error的分支——它只能识别函数返回的是T(即原联合类型),因此response仍会被标记为undefined | {nick:string}。
通过SuccessResult<T>条件类型,我们明确告知TypeScript:仅当传入的T包含error: undefined时返回该类型,否则返回never(错误分支已被抛出,不会走到return)。配合类型断言让TypeScript认可运行时判断,就能得到精确的类型。
更通用的简化写法(直接返回response数据)
如果只关心成功后的response数据,还可以进一步简化函数,直接返回response的类型:
type UnwrapSuccess<T> = T extends { error: any; response?: never } ? never : T extends { error?: never; response: infer R } ? R : never; function unwrapResult<T>(result: T): UnwrapSuccess<T> { if ('error' in result && result.error) { throw result.error; } return (result as any).response; } // 使用示例 const data = unwrapResult(test()) // data的类型直接是{nick:string},无需处理error属性 console.log(data.nick)
内容的提问来源于stack exchange,提问作者Ivan V.
相关产品推荐
相关产品推荐

