无法根据可观察结果调用函数

Unable to call functions on observable results

我有一个接口 (Vehicle),一个实现它的 class (Car) 和一些方法 (isColorRed):

export interface Vehicle{
   color : string;
}

export class Car implements Vehicle{
   color : string;
   
   constructor(obj){
      this.color = obj.color;
   }

   isColorRed(){
   return color === 'red' ? true : false;
   }
}

我正在从后端获取一个 Car 数组,并且只想存储红色的数组:

...
carsThatAreRed : Car[];
...
this.httpClient.get<Car[]>(carsUrl).pipe(
   map(cars => cars.filter(car => car.isColorRed()))
   ).subscribe(
   {
      next : (carsThatAreRed) => {
         this.carsThatAreRed = carsThatAreRed;
      }
   }
)

此请求失败并写入开发控制台

isColorRed() is not a function

当我从接收到的数组中的每个 Car 显式实例化 Car 个对象时,它起作用了。

...
.pipe(
   map(cars => cars.map(car => new Car(car)).filter(car => car.isColorRed()))
   )
...

为什么没有显式映射就不能工作?

这是一个运行时错误。你告诉 TypeScript 你得到的是它的 Cars,但在运行时它只是普通的 JSON 对象,上面没有 isColorRed 方法,除非你明确地将它们转换为 Cars。这样的事情

this.httpClient.get<Vehicle[]>(carsUrl)
    .pipe(
        map((vehicles) => vehicles.map(vehicle => new Car(vehicle))), // now we made Cars
        map(cars => cars.filter(car => car.isColorRed()))

我们在 typescript 中使用 as<> 所做的称为 Type assertions

  • 类型断言不会将plain javascript object转换成custom type object.

  • 类型断言是对compiler / IDE

    的提示
  • 类型断言 是一种告诉编译器“相信我,我知道我在做什么。”

  • 类型断言 没有运行时影响,仅供编译器使用。

看看编译后的JavaScript,你会看到类型断言(转换)消失了,因为它只是为了编译

这就是为什么 IDE / 编译器能够在 car.

之后显示建议 isColorRed

isColorRed 无法响应 [{plain javascript object}]

因此in-order要对汽车对象使用isColorRed方法,您需要使用javascript对象值实例化Car对象。

this.httpClient
  .get<Car[]>(carsUrl)
  .pipe(map((cars) => cars.filter((car: Car) => new Car(car).isColorRed())))
  .subscribe({
    next: (carsThatAreRed) => {
      this.carsThatAreRed = carsThatAreRed;
    },
  });