如何在 rxjs Angular 中使用管道内的两个 concatmap 时在订阅块内提取结果

How to extract result inside subscribe block while using two concatmap inside pipe in rxjs Angular

我有如下代码:

this.security.isLoggedIn$
        .pipe(
            distinctUntilChanged(),
            switchMap(
                (isLoggedInApp: boolean) =>
                    isLoggedInApp
                        ? of(true).pipe(
                                concatMap(() => this.security.getUser()),
                                concatMap(( partyId ) => this.loginService.getLendingType(partyId))
                        )
                        : of(false).pipe(finalize(() => this.router.navigateByUrl('login'))) //// TODO: needs refactoring, investigate routing
            )
        )
        .subscribe((result) => {
            console.log(result);
            //this log prints {"lendingType": "LendingPartner","partyId": "64f9f398-3a79-48d6-b4b7-89d41ccedb3b"}
        });

在上面的代码中,我的问题是,我想访问调用 getLendingType(partyId) 的结果。这是我的 getLendingType(partyId)

代码
  public getLendingType(partyId: string): Observable<{ lendingType: string, partyId: string }> {
return this.customerService.getCustomer(partyId).pipe(
    map((customer: ICustomer) => {
      return { lendingType: customer.LendingType, partyId: partyId } ;
    })
  );
}

所以 getLendingType 返回两个值。所以这里的问题是,我无法在订阅块中访问这两个值。但是,当我只返回一个值(例如 lendingType)时,我可以在订阅块中访问它。具体来说,我实际上在订阅块中获取了这两个值,正如您在日志打印中看到的那样。但是我不知道如何访问它们。如果我将鼠标悬停在可视代码中的结果上,它会显示结果由一个布尔值和一个对象组成,如下图所示。

我已经尝试了 result.lendingType 或结果 ['lendingType'],这会给我带来编译器错误,因为结果是一个复杂的对象,如图所示。在这种情况下,访问这两个值的方式是什么。

提前致谢。

您可以构建这样的类型检查:

if (typeof result !== "boolean"){
    console.log(result.lendingType)
}

Typescript 现在足够聪明,可以知道 result 不再是 boolean 类型。

您创建的管道 returns 如果用户已登录,则为 LendingData,如果用户未登录,则为布尔值 (false)。这就是为什么当您尝试访问 result.lendingTyperesult['lendingType'] 在失败案例 (!isLoggedInApp) 上,您的代码尝试执行以下操作:false.lendingType。这是不正确的,因此会引发错误。

如果您曾经对自己编写的管道感到困惑,我建议您通过拆分来简化它。这是很好的做法,您的同事稍后会感谢您。在这种情况下,在两个不同的管道中处理 LendingData 和导航。

/* ----------------- Deal with lending data ---------------- */

private getLendingData$ = this.security.getUser().pipe(
  switchMap((partyId) => this.loginService.getLendingType(partyId))
);

public lendingData$ = this.security.isLoggedIn$.pipe(
  distinctUntilChanged(),
  // if the user is logged in, return their lending data, else return null
  switchMap(isLoggedIn => iif(() => isLoggedIn, getLendingData$, of(null)),
  // so you don't make the API call more than once
  // for multiple subscribers
  shareReplay(1)
);

lendingData$.subscribe((result) => {
  // can return LendingData or null, therefore, access data with ?.
  // Ie) result?.lendingType
  console.log(result);
  // this log prints
  // { 
  //    "lendingType": "LendingPartner",
  //    "partyId": "64f9f398-3a79-48d6-b4b7-89d41ccedb3b"
  // }
});

/* ----------------- Deal with navigation ---------------- */

this.security.isLoggedIn$.pipe(
  distinctUntilChanged(),
  filter(isLoggedIn => !isLoggedIn)
).subscribe(() => {
  this.router.navigateByUrl('login'));
});