Angular5 HttpClient响应无法映射到TypeScript类问题求助
解决Angular 5 HttpClient响应映射到TypeScript类的问题
我太懂你这个困扰了!当初刚用Angular 5的HttpClient时,我也踩过一模一样的坑——明明给响应加了TypeScript类型断言,结果调用类里的hasPrivilege或者togglePrivilege方法时直接报错,后来才搞明白:HttpClient返回的只是JSON解析后的普通JavaScript对象,根本不是咱们定义的MaintainableUser类的实例!
先看你定义的类:
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); } } }
问题根源
当你这样写请求代码时:
this.http.get<MaintainableUser>('/api/users/1').subscribe(user => { console.log(user.hasPrivilege('admin')); // 这里会直接报错! });
TypeScript的get<MaintainableUser>只是编译时的类型提示,运行时HttpClient返回的还是普通JS对象,没有MaintainableUser类原型上的方法,所以调用方法自然会失败。
解决方案:手动创建类实例
我们需要在响应流中,把普通对象转换成真正的MaintainableUser实例,有两种常用方式:
方法一:直接在map中调用构造函数
利用RxJS的map操作符,把接口返回的对象传入类的构造函数,生成实例:
import { map } from 'rxjs/operators'; import { Observable } from 'rxjs'; // 你的用户服务类中 getUser(id: string): Observable<MaintainableUser> { return this.http.get<any>('/api/users/' + id).pipe( map(userData => new MaintainableUser(userData.id, userData.name, userData.privileges)) ); }
这样订阅时拿到的就是真正的类实例,调用方法完全正常:
this.userService.getUser('1').subscribe(user => { console.log(user.hasPrivilege('admin')); // 正常执行 user.togglePrivilege('editor'); // 也能正常触发方法 });
方法二:添加静态工厂方法简化操作
如果类的属性很多,构造函数传参太繁琐,可以给类加一个静态工厂方法,专门从JSON对象生成实例:
export class MaintainableUser { constructor(public id: string, public name: string, public privileges: string[]) { } // 新增静态工厂方法 static fromJson(json: { id: string; name: string; privileges: string[] }): MaintainableUser { return new MaintainableUser(json.id, json.name, json.privileges); } 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); } } }
然后服务中这样使用:
getUser(id: string): Observable<MaintainableUser> { return this.http.get<any>('/api/users/' + id).pipe( map(userData => MaintainableUser.fromJson(userData)) ); }
处理数组响应
如果接口返回的是用户数组,记得要逐个转换:
getUsers(): Observable<MaintainableUser[]> { return this.http.get<any[]>('/api/users').pipe( map(usersData => usersData.map(user => MaintainableUser.fromJson(user))) ); }
总结
TypeScript的类型断言不会在运行时转换对象的实际类型,只有手动创建类实例,才能让对象拥有类中定义的方法和属性行为。
内容的提问来源于stack exchange,提问作者Tarmo
相关产品推荐
相关产品推荐

