代码之家  ›  专栏  ›  技术社区  ›  Tarmo

无法将Angular5 HttpClient响应映射到我的typescript类

  •  2
  • Tarmo  · 技术社区  · 6 年前

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

    我有一个角度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);
          }
        );
      }
    
    }
    

    问题是,我收到的数据实际上并不是可维护用户的列表。my MaintainableUsersComponent的响应块具有以下输出:

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

    错误

    错误类型错误:\u v.context$含蓄的hasPrivilege不是函数

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

    3 回复  |  直到 6 年前
        1
  •  3
  •   krystianpe    6 年前

    理解类/对象如何工作是一个相当大的问题。从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)
     );
    }
    
        2
  •  1
  •   joh04667    6 年前

    你的 MaintainableUser 类型 映射很好,因此HttpResponse正确映射了泛型类型,Typescript编译器没有抱怨,但您的响应不是 例子 属于 可维护用户 。它仍然只是一个从JSON解析的对象。

    你的 可维护用户 类具有方法属性,这相当于将该方法添加到 MaintainableUser.prototype 。事实上,这正是Typescript编译器针对ES5所做的。

    请记住,Typescript类型具有 对传输的Javascript的影响。传递那个 MaintainableUser[] 键入到 HttpClient 只需在响应中添加强类型。本质上,您只是告诉IDE和编译器,响应是 可维护用户[] ,但它实际上不是 例子 属于 可维护用户 。您需要使用 new 传递原型的关键字。

    我会重构 可维护用户 接受该响应作为构造函数参数,并将该响应映射到 可维护用户 ,或移动 hasPrivelage 服务的方法。

        3
  •  0
  •   JusMalcolm    6 年前

    instanceof 检查原型链,因此除非 getAllMaintainableUsers() 正在创建新的 MaintainableUser 对象,它将返回false。我的猜测(从你的 getAllUsers() 是指您直接从服务返回对象。即使将类型注释为 MaintainableUser[] ,因为它不是使用的原型创建的 可维护用户 ,instanceof将不会为返回true data[0] instanceof MaintainableUser