指定 rxjs observable 的“错误”处理程序的类型

问题描述 投票:0回答:4

假设我有一些返回可观察值的操作。

this.loginService
  .post<IResponse>(url, { username, password })
  .subscribe(
    next => { /* I know the type of next */ },
    error => { /* Can I specify type of err, or is it always any? */ }
  );

next
的类型是我可以设置的 - 在本例中为
IResponse

error
怎么样 - 我可以以某种方式指定它的类型吗?或者它总是
any
,并且我总是需要在处理程序中进行类型转换?

angular typescript rxjs
4个回答
3
投票

根据我的经验,从 HTTP 操作生成可观察值的服务永远不应该发出未捕获的 HTTP 错误。它在该服务的使用者中创建了大量样板代码,并迫使使用者处理 HTTP 特定问题。

我还认为服务不应该捕获所有类型的错误,而应该捕获已知和预期的错误。要求应用程序本身使用错误拦截器处理边缘情况。

export interface ILoginResponse { //... } export interface IServiceResponse<TType> { success: boolean; payload?: TType; } @Injectable() export class LoginService { public login(options: any): Observable<IServiceResponse<ILoginResponse>> { return this.httpClient.post<ILoginResponse>('login', options).pipe( map(payload => ({success: true, payload})), catchError(err => { if(err instanceof HttpErrorResponse) { // handle http errors here, maybe retry, update headers, etc.. return of({success: false}); } // this error is unexpected, we don't know what to do // let the app interceptor handle it, but upstream observables // won't know what to do either. Our app has crashed... // You can return success false, but why handle this error? return throwError(err); }); } }

为什么要执行上述操作?

每当您使用发出未捕获错误的

route解析器时,它都会导致fail路由转换。路由器基本上会崩溃。用户基本上只会看到一个空白页面,因为解析器没有错误处理回退。

上面仅捕获 HTTP 错误,因为这是我们认为应该抛出的唯一类型。另一种错误应该被视为错误。

如果组件调用此服务,则程序员应在

信任

发出的值之前检查
success
标志是否为
true。如果业务逻辑不关心它是否失败,或者组件可以直观地向用户显示它无法执行 HTTP 请求,则可以对此进行过滤。无论哪种方式,HTTP 错误响应都不会发送到应用程序错误拦截器。

这只是一种

方法。人们以不同的方式处理 HTTP 事务。另一个答案正确回答了你的问题。


3
投票
您可以使用括号来表示您想要实现的目标:

this.loginService .post<IResponse>(url, { username, password }) .subscribe( (next: TypeOfYourResponse) => {...}, (error: TypeOfYourErrorResponse) => {...} );


有关箭头函数的进一步阅读:

https://www.tutorialsteacher.com/typescript/arrow-function

https://basarat.gitbooks.io/typescript/docs/arrow-functions.html


2024 年更新

由于 RxJS 已弃用自

subscribe()

 以来采用超过 1 个参数的所有 
v6.4
 签名,因此需要如下所示:

this.loginService .post<IResponse>(url, { username, password }) .subscribe({ next: (response: TypeOfYourResponse) => {...}, error: (err: TypeOfYourErrorResponse) => {...} });
    

2
投票
使用 catchError 运算符的另一种方法:

this.loginService .post<IResponse>(url, { username, password }) .catchError<TypeOfYourErrorResponse>(() => // Your catch callback) .subscribe( next => { /* I know the type of next */ }, );
    

0
投票
我真的很喜欢@Reactgular 接受的答案

我喜欢这样一个事实:它会让消费者在必须检查成功状态时思考错误!然而,有时消费者可能希望从服务器获取并显示错误,所以我对其进行了一些更改:

// DON'T FORGET THESE! import { Observable, of } from "rxjs"; import { catchError, map } from "rxjs/operators"; export interface ILoginResponse { //... } export interface IServiceResponse<TType> { payload?: TType; error?: HttpErrorResponse; } @Injectable() export class LoginService { public login(options: any): Observable<IServiceResponse<ILoginResponse>> { return this.httpClient.post<ILoginResponse>('login', options).pipe( map(payload => ({ payload })), catchError(err => of({ error: err })) } }
不需要成功标志,只需检查是否有有效负载或错误

loginService.login().subscribe(response => { if (response.payload) { // success... } else if (response.error) { // handle the error } },
我认为返回所有错误,客户可能不关心,因此可以忽略它,但如果他们关心的话,它就会存在;如果您想处理特定错误,请在其他地方使用 

HttpInterceptor

...

© www.soinside.com 2019 - 2024. All rights reserved.