web-dev-qa-db-fra.com

Type 'Observable <Réponse | Observable <Response >> 'n'est pas assignable au type' Observable <Response> '

J'ai un service simple avec le contenu suivant:

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

Il fonctionnait parfaitement, jusqu’à J’ai mis à jour TypeScript de 2.3.4 à 2.4.1.

Maintenant, après la mise à niveau, j'obtiens l'erreur bizarre:

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

Quel est le point ici? Quels sont les changements dans TS 2.4.x qui font que mon application ne fonctionne plus correctement?

7
dev_054

TypeScript 2.4 introduit une meilleure vérification pour les génériques. Il met en évidence les erreurs dans votre code qui devraient être corrigées.

Par exemple, le type de retour handleSuccess ne correspond pas à ce qu'il renvoie; il retourne un objet anonyme, mais il est saisi en retournant Observable<Response>. Et comme il est utilisé avec map, vous vous retrouvez avec un observable composé qui est tapé comme Observable<Response | Observable<Response>>.

Les erreurs que vous voyez sont réelles et devraient être corrigées.

6
cartant

Le changement est une vérification de type plus forte. 

Un Observable<Response> n'est pas assignable à quelque chose qui est typé Response car ils sont de types différents. Par souci de brièveté, appelons ces types X et Y

Observable<X | Y> n'est pas assignable à quelque chose de type Y car, s'il peut contenir un Y, il peut également contenir un X, ce qui est rejeté par la vérification plus stricte introduite dans la version 2.4.1. 

Capturez la valeur de votre expression dans une variable let et renvoyez cette variable. Ensuite, vous pourrez inspecter le type de la variable, ce qui vous montrera qu’elle n’est pas compatible au même titre que le compilateur.

Pour que votre code soit compilé, vous devez tester une instance du type correct avant le casting.

Si vous n'avez pas le temps de nettoyer votre base de code, vous pouvez rappeler la vérification de type plus forte avec --noStrictGenericChecks

Voici du vrai code TS avec un problème parallèle au vôtre. Dans cet exemple, FieldInstance n'a pas de propriété Form, mais FormInstance en a une, ce qui me permet de les distinguer et de gérer l'ambiguïté du type. FieldInstanceRepeater est assignable à FieldInstance car il s'agit d'un descendant.

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;
  ...
}
2
Peter Wone

Pensez à faire les changements suivants:

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

Les nouvelles versions de TypeScript ont introduit une détection plus forte des types/génériques, de sorte que le compilateur se plaint de vos méthodes actuelles, car leurs types de retour ne correspondent tout simplement pas. 

Dans la dernière version d'angular, le client HTTP a été refait pour éviter l'analyse de POJO non typés (appelant r.json()). À cette fin, les nouvelles méthodes http étant génériques, les développeurs peuvent désormais mapper directement dans un type lors de l'extraction du contenu de la réponse. Pour plus d'informations, consultez ce lien

0
Jota.Toledo