类型'Observable<Response | Observable<Response>>'无法赋值给类型'Observable<Response>'。

8

我有一个简单的服务,内容如下:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';

import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AddressService {

  constructor(private http: Http) { }

  getAnything = (): Observable<Response> => {
    return this.http.get('https://my_api.com')
      .map(this.handleSuccess)
      .catch(this.handleError);
  }

  handleError = (error: Response): Observable<Response> => {
    return Observable.throw(error || 'Server Error');
  }

  handleSuccess = (response: Response): Observable<Response> => {
    let body;

    if (response.text()) {
      body = response.json();
    }

    return body || {};
  }
}

一切都很完美,直到我把Typescript版本从2.3.4升级到2.4.1。

现在,在升级后,我遇到了一个奇怪的错误:

Type 'Observable<Response | Observable<Response>>' is not assignable to type 'Observable<Response>'

这里的关键是什么?TS 2.4.x有哪些变化会导致我的应用程序无法正常工作?


1
你为什么要升级到2.4.x版本?https://dev59.com/HlcP5IYBdhLWcg3wJ3KJ#44793989 - CharanRoot
@Jonnysai,我不确定我是否理解了...你是在说我不能升级到2.4.1吗? - dev_054
1
handleSuccess = (response: Response): Observable<Response>并没有返回一个Observable,而是任意类型。你的返回类型错误,现在编译器报错是一个好迹象。 - Jota.Toledo
我猜错误出在 handleSuccess 函数上,它没有返回 Observable,而只是返回类似 JSON 的对象,对吗? - Nodarii
3个回答

7

TypeScript 2.4引入了更好的泛型检查,它会突出显示代码中需要修复的错误。

例如,handleSuccess的返回类型与它实际返回的不匹配;它返回了一个匿名对象,但是被定义为返回Observable<Response>。由于它被用于map,你最终得到的组合observable的类型是Observable<Response | Observable<Response>>

你看到的错误是真实存在的,应该被修复。


1
你的 handleSuccess 方法并没有返回 Observable<Response>。请查看 HTTP 文档 https://tools.ietf.org/html/rfc2616#section-6 。你返回了一个 JSON 负载或者一个空对象。 - JGFMK

2
变化是更强的类型检查。
一个Observable<Response>不能分配给被定义为Response类型的变量,因为它们是不同的类型。为了简洁起见,我们称这些类型为XYObservable<X | Y>不能分配给被定义为Y类型的变量,因为它可能包含Y,但也可能包含X,而在2.4.1版本中引入了更严格的检查,会拒绝这种情况。
将表达式的值捕获到一个let变量中,并返回该变量。然后您将能够检查变量的类型,就像编译器报告的那样,它不兼容。
为了使您的代码编译通过,应在进行转换之前测试是否为正确类型的实例。
如果您没有时间清理代码库,则可以使用--noStrictGenericChecks来降低更强的类型检查。
以下是一些与您的问题类似的真实TS代码示例。在此示例中,FieldInstance缺少Form属性,但FormInstance有一个,这使我能够区分它们并处理类型的歧义。FieldInstanceRepeater可分配给FieldInstance,因为它是一个后代。
constructor(scope: FormInstance | FieldInstanceRepeater, field: IFormFieldRow) {
  this.FormInstance = ((function getFormInstance(fi: FormInstance | FieldInstance): FormInstance | FieldInstance {
    let isFormInstance = !!(fi as FormInstance).Form;
    return isFormInstance ? fi : getFormInstance((fi as FieldInstance).Scope);
  })(scope) as FormInstance);
  this.Scope = scope;
  ...
}

0

考虑进行以下更改:

import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
import { _throw } from 'rxjs/observable/throw';

export interface Data{} // an interface to define the object in JSON format returned by your backend

@Injectable()
export class AddressService {

  constructor(private http: Http) { }

  getAnything = (): Observable<Data> => {
    return this.http.get('https://my_api.com')
      .map(this.handleSuccess)
      .catch(this.handleError);
  }

  handleError = (error: Response) : ErrorObservable { // The return type is ErrorObservable, which is a specialization of Observable<any>
    return _throw(error || 'Server Error');
  }

  handleSuccess = (response: Response) { // the return here is any, as you dont know how do the POJO(s) generated by response.json() look like
    let body;

    if (response.text()) {
      body = response.json();
    }

    return body || {};
  }
}

新版本的TypeScript引入了更强的类型/泛型检测,这就是为什么编译器会抱怨您当前的方法,因为它们的返回类型不匹配。

在最新版本的Angular中,HTTP客户端已经重新设计,以避免解析未经类型化的POJO(调用r.json())。为此,新的HTTP方法是通用的,因此开发人员现在可以在提取响应内容时直接映射到类型。有关更多信息,请查看this link


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接