可观察和接口

时间:2017-09-27 20:04:58

标签: angular typescript interface casting

我为模型定义了以下界面:

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这样的其他语言?

1 个答案:

答案 0 :(得分:2)

您的代码中存在两个问题。

  1. 您的handleResponse方法的返回类型为Observable<IModel>。并且您尝试从支持返回Observable<Token>的方法返回该值。所以这不正确:所有IModel实例都不是Token的实例。

  2. 您的handleResponse方法实际上返回Observable<void>,因为在map()回调中,您返回fillFromResponse()的结果,以及fillFromResponse()的返回类型是无效的。

  3. 所以,代码应该看起来像这样(未经测试):

    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。