【问题标题】:Observable and interfaces可观察和接口
【发布时间】:2018-03-09 10:36:02
【问题描述】:

我为模型定义了以下接口:

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;
    }
}

我希望所有可观察的地图或捕获函数都有一个回调:

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 不可分配给 Observable

为什么接口不像 PHP 等其他语言那样工作?

【问题讨论】:

    标签: angular typescript interface casting


    【解决方案1】:

    你的代码有两个问题。

    1. 您的 handleResponse 方法的返回类型是 Observable&lt;IModel&gt;。而您正试图从一个应该返回Observable&lt;Token&gt; 的方法中返回它。所以这是不正确的:所有 IModel 实例都不是 Token 的实例。

    2. 你的handleResponse方法实际上返回了一个Observable&lt;void&gt;,因为在map()回调中,你返回的是fillFromResponse()的结果,而fillFromResponse()的返回类型是void。

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

    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() 返回的 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。

    【讨论】:

      猜你喜欢
      • 2015-02-06
      • 2016-07-06
      • 2013-02-12
      • 1970-01-01
      • 2018-11-22
      • 2016-08-26
      • 1970-01-01
      • 2011-06-17
      • 2014-06-22
      相关资源
      最近更新 更多