无法将Angular5 HttpClient响应映射到我的打字稿类

时间:2018-03-26 20:18:53

标签: angular typescript angular5 angular-httpclient

我在将Angular 5 HttpClient响应映射到具体的TypeScript类时遇到问题。

我有以下Angular 5课程:

export class MaintainableUser {

  constructor(public id: string, public name: string, public privileges: string[]) {
  }

  public hasPrivilege(privilege: string): boolean {
    return this.privileges.indexOf(privilege) != -1;
  }

  public togglePrivilege(privilege: string) {
    if (this.hasPrivilege(privilege)) {
      this.privileges.splice(this.privileges.indexOf(privilege), 1);
    } else {
      this.privileges.push(privilege);
    }
    console.log(this.privileges);
  }
}

我有以下Angular5服务:

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {MaintainableUser} from './maintain-users/maintainable-user';
import {Observable} from 'rxjs/Observable';
import {catchError} from 'rxjs/operators';
import {ApiErrorHandler} from '../api-error-handler';

@Injectable()
export class AdminService {

  constructor(private http: HttpClient, private errors: ApiErrorHandler) {
  }

  getAllUsers(): Observable<MaintainableUser[]> {
    return this.http.get<MaintainableUser[]>('api/admin/users').pipe(catchError(this.errors.handle));
  }

}

这很干净,现在我可以像这样使用我的服务:

import {Component, OnInit} from '@angular/core';
import {MaintainableUser} from './maintainable-user';
import {AdminService} from '../admin.service';

@Component({
  selector: 'app-maintain-users',
  templateUrl: './maintain-users.component.html',
  styleUrls: ['./maintain-users.component.scss']
})
export class MaintainUsersComponent implements OnInit {

  constructor(private adminService: AdminService) {
  }

  ngOnInit() {
    this.reloadMaintainableUsers();
  }

  private reloadMaintainableUsers() {
    this.adminService.getAllMaintainableUsers().subscribe(
      data => {
        console.log(data);
        console.log(data[0] instanceof MaintainableUser);
        data[0].hasPrivilege('ADMIN');
      },
      err => {
        console.log('Service error: ' + err);
      }
    );
  }

}

问题是我收到的数据实际上并不是MaintainableUser的列表。来自我的MaintainableUsersComponent的响应块具有以下输出:

  

{“id”:“john”,“name”:“John Doe”,“privileges”:[“ADMIN”]}

     

     

ERROR TypeError:_v.context。$ implicit.hasPrivilege不是函数

为什么?为什么我的数据[0]不是MaintainableUser的实例?我对Angular很新,但我从不同的教程中了解到,从版本4开始,我应该能够自动映射到我的类/接口。或者它只是一个假的东西,所以你可以安全地对象是强类型的,但你不能确定它是实际对象本身的实例?如果我可以在我的响应类中有一些辅助方法,那将是非常好的,所以我可以在视图中使用它们,但是目前我还没有找到一种干净的方法来实现它。

3 个答案:

答案 0 :(得分:3)

理解类/对象如何工作是一个相当大的问题。从API返回的只是一个普通的对象(解析的JSON),它没有MaintainableUser的任何方法,因为它不是你的类的实例。它只与您的班级具有相同的属性。

您需要手动将值从对象传递到构造函数并创建类的实例。 Angular不会自动执行此操作。我经常做这样的事情:

export class MaintainableUser {

  public static createInstance({ id, name, privileges }): MaintainableUser {
    return new MaintainableUser(id, name, privileges);
  }

  constructor(public id: string, public name: string, public privileges: string[]) {}

  public hasPrivilege(privilege: string): boolean {
    return this.privileges.indexOf(privilege) != -1;
  }

  public togglePrivilege(privilege: string) {
    if (this.hasPrivilege(privilege)) {
      this.privileges.splice(this.privileges.indexOf(privilege), 1);
    } else {
      this.privileges.push(privilege);
    }
    console.log(this.privileges);
  }
}

然后:

getAllUsers(): Observable<MaintainableUser[]> {
  return this.http.get<MaintainableUser[]>.('api/admin/users').pipe(
    map(MaintainableUser.createInstance)
    catchError(this.errors.handle)
 );
}

答案 1 :(得分:1)

您的MaintainableUser 类型正在映射得很好,因此HttpResponse正确映射该泛型类型而且Typescript编译器并不抱怨,但您的响应不是< MaintainableUser的em> instance 。它仍然只是一个从JSON解析的对象。

您的MaintainableUser类有一个方法属性,相当于将该方法添加到MaintainableUser.prototype。事实上,这正是Typescript编译器在针对ES5时的作用。

请记住,Typescript类型对已转换的Javascript具有 no 效果。将MaintainableUser[]类型传递给HttpClient只会为响应添加强类型。从本质上讲,您只是告诉IDE和编译器响应是MaintainableUser[],但它实际上并不是MaintainableUser实例。您需要使用new关键字来传递该原型。

我重构MaintainableUser以接受响应作​​为构造函数参数,并将响应映射到MaintainableUser的新实例,或将hasPrivelage方法移动到服务。

答案 2 :(得分:0)

instanceof检查原型链,因此,除非您的getAllMaintainableUsers()正在创建新的MaintainableUser对象,否则它将返回false。我的猜测(来自您上面的getAllUsers()调用)是您直接从服务返回一个对象。即使您将类型注释为MaintainableUser[],由于它不是使用MaintainableUser的原型创建的,因此instanceof对data[0] instanceof MaintainableUser不会返回true。