【问题标题】:Specify type of rxjs observable's "error" handler指定 rxjs observable 的“错误”处理程序的类型
【发布时间】:2019-06-10 22:00:18
【问题描述】:

假设我有一些操作会返回一个 observable。

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,我总是需要在处理程序中进行类型转换?

【问题讨论】:

  • 你永远不能假设 observable 捕获的错误类型。您可以使用 instantof 运算符在运行时检查类型。我所做的是捕获服务中的所有错误,然后只转发给定类型的错误。然后,该服务的消费者可以假设下游的错误类型。
  • @Reactgular 这是我最初的假设,直到我看到下面的答案 - 你可能有一个例子吗?我也不想假设类型,感觉就像我在打破类型系统。

标签: angular typescript rxjs


【解决方案1】:

根据我的经验,从 HTTP 操作产生 observables 的服务不应该发出未捕获的 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 的处理方式都不同。另一个答案正确回答了您的问题。

【讨论】:

  • @lonix 你应该考虑这些建议
  • 我认为这是个坏建议。您所做的只是将错误状态转换为布尔成功状态。消费者仍然需要处理该布尔标志,并且您创建了更多包含该标志的样板接口。第二个原因也是错误的。解析器可以提供需要来显示视图的数据。如果数据不存在,例如在success = false的情况下,则无法显示视图。您可以(并且应该)仍然使用 catchError 管理解析器中的可观察错误并重定向到适当的视图。
【解决方案2】:

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

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

【讨论】:

  • 我不记得了,但我认为您必须为catchError 定义两个通用参数。也许是错误类型和返回类型。我不确定签名是否接受单个参数。
【解决方案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

【讨论】:

  • 啊,真没想到。顺便说一句,如果是错误的类型,它会抛出错误还是继续?
  • afaik,它不适用于运行时,因为 JavaScript 在运行时没有类型。但它是用于编译时的。顺便说一句,我不是 100% 确定
  • 如果它的类型错误,它将默默地继续运行并且可能在运行时失败。这是涉及未经检查的any 时的一般规则。
猜你喜欢
  • 1970-01-01
  • 2021-11-02
  • 2020-10-06
  • 1970-01-01
  • 2016-08-23
  • 1970-01-01
  • 2019-05-18
  • 2019-09-22
  • 2019-04-08
相关资源
最近更新 更多