我为模型定义了以下界面:
export interface IModel {
fillFromResponse(body: any);
}
所以,在一个模型中(例如,Token)我强制接口:
import { IModel } from './imodel';
export class Token implements IModel {
public value: string;
public fillFromResponse(body: any) {
let token = new Token();
token.value = body.access_token;
return token;
}
}
我希望对所有可观察的map或catch函数都有一个回调:
public handleResponse(instance: IModel, observable: Observable<Response>): Observable<IModel> {
return observable.map(
(response: Response) => {
return instance.fillFromResponse(response.json());
}
).catch((error: any) =>
Observable.throw(error.json().messages[0] || 'Unknown error')
);
}
所以,在服务中我有以下方法:
public login(credentials): Observable<Token> {
let url = this.api.getUrl('/users/tokens');
let options = this.api.getOptions();
return this.api.handleResponse(
new Token(),
this.http.post(url, credentials, options)
);
}
但我明白了:
类型Observable&lt; IModel&gt;不能分配给Observable&lt;令牌&gt;
为什么界面不像PHP这样的其他语言?
答案 0 :(得分:2)
您的代码中存在两个问题。
您的handleResponse方法的返回类型为Observable<IModel>
。并且您尝试从支持返回Observable<Token>
的方法返回该值。所以这不正确:所有IModel实例都不是Token的实例。
您的handleResponse方法实际上返回Observable<void>
,因为在map()回调中,您返回fillFromResponse()的结果,以及fillFromResponse()的返回类型是无效的。
所以,代码应该看起来像这样(未经测试):
export interface IModel<T> {
fillFromResponse(body: any): T;
}
export class Token implements IModel<Token> {
public value: string;
public fillFromResponse(body: any): Token {
let token = new Token();
token.value = body.access_token;
return token;
}
}
或者更确切地说,因为我猜你实际上想要填充原始令牌而不是创建一个新令牌:
export class Token implements IModel<Token> {
public value: string;
public fillFromResponse(body: any): Token {
this.value = body.access_token;
return this;
}
}
最后
public handleResponse<T>(instance: IModel<T>, observable: Observable<Response>): Observable<T> {
return observable.map(
(response: Response) => instance.fillFromResponse(response.json());
).catch((error: any) =>
Observable.throw(error.json().messages[0] || 'Unknown error')
);
}
那就是说,我认为所有这些都是一个坏主意,并使事情变得比应有的复杂得多。如果你真的想要一个通用的handleResponse方法,你可以传递回调函数传递给map()运算符。但这样做是没用的,因为你可以简单地在handleResponse()int首先返回的observable上调用map():
public login(credentials): Observable<Token> {
let url = this.api.getUrl('/users/tokens');
let options = this.api.getOptions();
return this.api.handleResponse(
this.http.post(url, credentials, options)
).map(body => new Token(body.access_token));
}
另请注意,如果您使用新的HttpClient而不是很快弃用的Http服务,您甚至不必将响应映射到json。