TypeScript异步方法try/catch中err报unknown类型的原因及解决办法
报错原因
这个现象的本质是TypeScript的类型校验规则导致,和异步方法本身没有直接关联:
- TypeScript 4.4及以上版本新增了
useUnknownInCatchVariables编译选项,开启该选项后,所有catch块捕获的错误变量默认类型为unknown,而非早期版本的any,unknown类型的变量不允许直接访问任意属性,所以会触发你遇到的报错。 - 你观察到的同步方法无报错、异步方法报错的差异,通常是两个原因导致:一是你的项目TS配置对异步代码的类型校验严格度更高,二是同步方法的catch块要么没有访问err的属性,要么已经提前做了类型适配,没有触发校验逻辑。
- 异步方法中await操作可能抛出的错误类型本身无法提前预知,TS也会针对这类场景默认做更严格的类型检查,所以会优先触发unknown类型的提示。
修复方案
你可以根据项目的实际情况选择以下任意一种方案:
方案1:类型收窄处理(最安全,推荐)
先判断err的类型再访问属性,完全符合TS的类型安全要求,也能兼容运行时可能抛出非Error类型值的极端场景:
async createOrganization(dbSession: ClientSession, organization: IOrganization): Promise<IOrganization> { try { // @ts-ignore const newOrganization = new this.Model(organization) // @ts-ignore await newOrganization.save() // @ts-ignore return newOrganization } catch (err: unknown) { if (err instanceof Error) { throw new OrganizationCreationError(err.message) } // 处理非Error类型的抛出值 throw new OrganizationCreationError(String(err)) } }
方案2:全局关闭catch变量的unknown校验
如果项目不需要这么严格的类型校验,可以直接修改tsconfig.json的编译配置:
{ "compilerOptions": { "useUnknownInCatchVariables": false } }
配置生效后所有catch块的err变量默认会是any类型,不会再触发该报错,但是会损失类型安全性,不推荐中大型项目使用。
方案3:类型断言快速修复(临时应急用)
如果确定当前场景抛出的错误一定是Error类实例,可以直接用类型断言绕过校验,写法最简单:
catch (err) { throw new OrganizationCreationError((err as Error).message) }
注意该方案没有运行时校验,如果实际抛出的不是Error实例,会导致访问message属性时报错,只适合临时应急使用。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

