Angular结合@ngneat/query时,访问t.error.errorCode触发TypeScript类型错误的原因及类型修正方法
Angular结合@ngneat/query时,访问t.error.errorCode触发TypeScript类型错误的原因及类型修正方法
嗨,我来帮你搞定这个问题~
为啥会出现这个类型错误?
其实原因很简单:@ngneat/query 的 result$ 流默认会把错误对象的类型推断为原生的 Error 类(就是JS里自带的那个Error),但你代码里抛出的是一个自定义的普通对象 { errorCode: number },它和原生Error的结构完全不一样——原生Error只有message、name这些属性,根本没有errorCode,所以TypeScript自然会提示你这个属性不存在啦。
靠谱的解决办法
方法1:自定义错误类型 + 显式指定泛型(推荐)
这是最规范的做法,能让整个代码的类型都保持一致,避免后续的类型问题。
首先,先定义你需要的自定义错误类型和接口:
// 定义API返回的数据类型 interface TodoApiResponse { data: { status: number }; } // 定义你抛出的自定义错误类型 interface CustomApiError { errorCode: number; }
然后,在调用 injectQuery 的时候,通过泛型参数显式指定数据类型和错误类型(@ngneat/query 的 query 方法支持 <TData, TError> 两个泛型参数):
export class App { #query = injectQuery(); // 这里通过<TodoApiResponse, CustomApiError>指定数据和错误类型 todos = this.#query<TodoApiResponse, CustomApiError>({ queryKey: ['todos'], queryFn: () => of({ data: { status: 500 } }).pipe( tap((response) => { if (response.data.status === 500) { // 这里可以明确断言为自定义错误类型 throw { errorCode: response.data.status } as CustomApiError; } }) ), }).result$; ngOnInit() { this.todos.subscribe((t) => { // 现在t.error的类型就是CustomApiError,TS不会再报错啦 const errorCode = t.error?.errorCode; }); } }
对应的HTML模板里,也能自动获得类型提示,不需要额外处理:
<div *ngIf="todos | async as todos"> <div *ngIf="todos.error">error code: {{ todos.error.errorCode }}</div> </div>
方法2:局部类型断言(临时快速解决)
如果你只是想快速绕过这个错误,不想改全局的泛型,可以在访问errorCode的时候用类型断言:
this.todos.subscribe((t) => { // 把t.error断言为你的自定义错误类型 const errorCode = (t.error as { errorCode: number })?.errorCode; });
模板里也可以用同样的方式:
<div *ngIf="todos | async as todos"> <div *ngIf="todos.error">error code: {{ (todos.error as { errorCode: number }).errorCode }}</div> </div>
不过这种方法只适合临时场景,长期来看还是泛型指定更靠谱,能避免隐藏的类型问题。
方法3:自定义Error子类(更贴近原生Error规范)
如果你想兼顾原生Error的特性(比如栈追踪),同时添加自定义属性,可以创建一个Error的子类:
class CustomApiError extends Error { constructor(public errorCode: number) { super(`Error code: ${errorCode}`); this.name = 'CustomApiError'; } }
然后在抛出的时候用这个子类:
throw new CustomApiError(response.data.status);
这种情况下,TypeScript会自动识别错误类型,不需要额外指定泛型,而且还能保留原生Error的所有功能。
备注:内容来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

