我在将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开始,我应该能够自动映射到我的类/接口。或者它只是一个假的东西,所以你可以安全地对象是强类型的,但你不能确定它是实际对象本身的实例?如果我可以在我的响应类中有一些辅助方法,那将是非常好的,所以我可以在视图中使用它们,但是目前我还没有找到一种干净的方法来实现它。
答案 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。