在 Angular 上订阅 2 种类型的可观察对象

Subscribing to observable of 2 types on Angular

对不起标题,但我找不到更好的标题。

我在发送 GET 命令时调用 return 是 json object 的 HTTP API,但如果资源不足,它将 return 404没有找到。 我正在使用 Angular 9 并且我正在尝试找到一种方法来从服务输出 json object 或 return 上接收到的 HTTP 错误的枚举值同一个 Observable。

请看下面的一些代码:

device.service.ts

getDevice(objectID: number | string): Observable<Device | ResponseStatus> {
    return this.http.get<Device>(`http://localhost:8080/Registration/Device/${objectID}`)
      .pipe(
        catchError(this.handleError)
      );
  }
handleError(error: HttpErrorResponse): Observable<ResponseStatus> {
    switch (error.status) {
      case 404: {
        return of(ResponseStatus.objectNotFound);
        break;
      }
      case 409: {
        return of(ResponseStatus.objectAlreadyExists);
        break;
      }
    }
  }

我希望 return ResponseStatus 到我的组件,这样我就可以用同样的方式处理所有错误。

device-item-resolver-service.ts

export class DeviceItemResolverService implements Resolve<Device> {

  constructor(private ds: DeviceService, private router: Router) { }
  
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Device> | Observable<never> {

    let objectID = route.paramMap.get('objectID');

    return this.ds.getDevice(objectID).pipe(
      take(1),
      mergeMap(
        (item: Device) => {
          if (item) {
            return of(item);
          }
          else {
            this.router.navigate(['/devices']);
            return EMPTY;
          }
        }
      )
    );
  }
}

显然一切都很顺利。 运行 我可以接收设备的程序,但我找不到在解析器上处理 ResponseStatus 的方法。

拜托,你能帮帮我吗?

不需要使用 mergeMap,因为在这种情况下 map 应该足够好。

import { map } from 'rxjs/operators';
....
return this.ds.getDevice(objectID).pipe(
      take(1),
      map(
        (item: Device | ResponseStatus) => {
          // this if statement I think is the culprit.
          // Basically ResponseStatus.objectNotFound is true and it goes here
          // I am not sure if instanceof will work but basically you have to find out 
          // if you're getting Device or ResponseStatus and act accordingly
          if (item instanceof Device) {
            return item;
          }
          else {
            this.router.navigate(['/devices']);
            return null;
          }
        }
      )
    );

我无法按照建议使用 typeofinstanceof,所以我在 typescript 中找到了一篇关于高级类型的很棒的文档,如下所示: https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards

看看下面我是如何解决这个问题的:

首先我定义了一个用户定义的类型保护:

function isDevice(value: Device | ResponseStatus): value is Device {
      return (value as Device).objectID !== undefined;
    }

然后我在我的原始代码上调用了这个函数:

return this.ds.getDevice(objectID).pipe(
      take(1),
      mergeMap(
        (item: Device | ResponseStatus) => {
          if (!item) {
            this.router.navigate(['/devices']);
            return EMPTY;
          }
          else if (isDevice(item)) {
            return of(item)
          }
          else {
            switch (item as ResponseStatus) {
              case ResponseStatus.objectNotFound: {
                this.router.navigate(['/devices']);
                return EMPTY;
              }
            }
          }
        }
      )
    )        
  }

请注意,我需要使用 mergeMapmap 没用。