Ошибки после перенастройки Angular и RxJS с 5 по 6 - Тип 'Observable <{}>' нельзя назначить типу "Observable <....>" - PullRequest
0 голосов
/ 03 октября 2018

Я перенес проект Angular с v5 на v6.

Чтобы обновить все операции импорта, я уже выполнил rxjs-5-to-6-migrate:

npm install -g rxjs-tslint
rxjs-5-to-6-migrate -p src/tsconfig.app.json

Но теперь у меня есть ОШИБКИ, подобные следующей:

src/app/products/product.service.ts(54,4): error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<{ count: number; next: string; previous: string; results: any[]; }>'.
  Type '{}' is not assignable to type '{ count: number; next: string; previous: string; results: any[]; }'.
    Property 'count' is missing in type '{}'.

product.service.ts :

import { Injectable } from '@angular/core';
//import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';

import { catchError, map, tap, finalize } from 'rxjs/operators';

import { Product } from './product';

import { SpinnerService } from './../utilities/spinner/spinner.service';

import { environment } from '../../environments/environment';

const endpoint = environment.apiHost+'/api/products/' //'http://127.0.0.1:8000/api/products/'

@Injectable()
export class ProductService {

  /* Caching few data that does not change so often */
  private productTypes: any[];
  private departments: any[];
  private authors: any[];
  private colors: any[];
  private sizeRuns: any[];

  constructor(private http: HttpClient, private _spinnerService: SpinnerService) { }

  list(params?): Observable<{count:number, next:string, previous:string, results: any[]}> {
    return this.http.get<{count:number, next:string, previous:string, results: any[]}>(endpoint, {params: params})
      .pipe(
        catchError(this.handleError<any>('Retrieving products'))
      );
  }

  /**
   * Handle Http operation that failed.
   * Let the app continue.
   * @param operation - name of the operation that failed
   * @param result - optional value to return as the observable result
   */
  private handleError<T>(operation='Operation', result?: T) {
    return (error: any): ErrorObservable | Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      console.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an Observable with empty result.
      //return of(result as T); 
      return new ErrorObservable(error);
    };
  }

}

Я видел другие подобные вопросы в StackOverflow, но все еще не понимаю, как решить,Я, вероятно, могу изменить интерфейс {count:number, next:string, previous:string, results: any[]} на простой any, но я не хочу этого делать.Любое решение?

ОБНОВЛЕНИЕ1 : Использование интерфейса

interface PaginatedList {
  count: number;
  next: string;
  previous: string;
  results: any[];
}

@Injectable()
export class ProductService {

  /* Caching few data that does not change so often */
  private productTypes: any[];
  private departments: any[];
  private authors: any[];
  private colors: any[];
  private sizeRuns: any[];

  constructor(private http: HttpClient, private _spinnerService: SpinnerService) { }

  list(params?): Observable<PaginatedList> {
    this._spinnerService.show('productListSpinner');
    return this.http.get<PaginatedList>(endpoint, {params: params})
      .pipe(
        catchError(this.handleError<any>('Retrieving products')),
        finalize(() => this._spinnerService.hide('productListSpinner'))
      );
  }

  /**
   * Handle Http operation that failed.
   * Let the app continue.
   * @param operation - name of the operation that failed
   * @param result - optional value to return as the observable result
   */
  private handleError<T>(operation='Operation', result?: T) {
    return (error: any): ErrorObservable | Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      console.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an Observable with empty result.
      //return of(result as T); 
      return new ErrorObservable(error);
    };
  }

}

ОШИБКИ :

src/app/products/product.service.ts(61,4): error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<PaginatedList>'.
  Type '{}' is not assignable to type 'PaginatedList'.
    Property 'count' is missing in type '{}'.

ОБНОВЛЕНИЕ2:

Проверяя мои ошибки, я думаю, что ErrorObservable вызывает другие ошибки:

src/app/products/product.service.ts(325,26): error TS2314: Generic type 'ErrorObservable<T>' requires 1 type argument(s).

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

Я, вероятно, могу изменить интерфейс {count: number, next: string, previous: string, results: any []} на просто any`

Делая это, вы простовыстрелил себе в ногу.Почему бы вам не определить интерфейс концепции, которую вы знаете?

Первый вопрос, который вы должны задать себе при обработке ошибки: мне нужно изящно или неблагодарно обработать это?

Изящно обработка ошибки превратит его в «фальшивое» уведомление в потоке, сохраняя контракт типа в большинстве случаев.Например:

import { throwError, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
// Create source Observable<string> that emits an error
const source : Observable<string> = throwError('This is an error!');
// Gracefully handle error, returning observable with error message
// Notice that the type contract of the source is mantained
const example : Observable<string> = source.pipe(catchError(val => of(`I caught: ${val}`)));
// Output: 'I caught: This is an error'
// Notice that the next, and not the error callback, is invoked
const subscribe = example.subscribe(
      val => console.log(val), 
      error => console.log("Something exploded: ", error));

В предыдущем примере я сохранял контракт типа источника.В следующем я не могу:

import { throwError, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
// Create source Observable<string> that emits an error
const source : Observable<string> = throwError('This is an error!');
// Gracefully handle error, returning observable with error message
// Notice that by mapping the error to a fake notification of another type, the new
// stream extends the type contract of the source
const example : Observable<string | number> = source.pipe(catchError(val => of(1)));
// Output: 'I caught: This is an error'
// Notice that the next, and not the error callback, is invoked
const subscribe = example.subscribe(
      val => console.log(val), 
      error => console.log("Something exploded: ", error));

Другой вариант - неблагоразумно обработать ошибку, в основном применяя некоторую логику, а затем повторно выбрасывая.В таком случае контракт типа для потока не имеет информации об ошибке, из-за которой может возникнуть поток .Например:

import { throwError, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
// Create source Observable<string> that emits an error
const source : Observable<string> = throwError('This is an error!');
// Ungracefully handle error, re-throwing an object
const example : Observable<string> = source.pipe(catchError(error => throwError({message: 'Error caught', error})));
// Output: 'Something exploded: '
// Notice that the error, and not the next callback, is invoked
const subscribe = example.subscribe(
      val => console.log(val), 
      error => console.log("Something exploded: ", error));

Вернуться к вашей проблеме;в настоящее время ваш подход изящно обрабатывает ошибку и расширяет контракт типа для исходного потока, без правильного объявления возвращаемого типа метода.

Решение ошибки будетизменить сигнатуру метода на:

list(params?): Observable<PaginatedList | any>;

Другая проблема заключается в том, что вы напрямую используете ErrorObservable, что действительно является подробностью реализации.Обычно вы используете оператор throwError.

0 голосов
/ 03 октября 2018

Вы можете определить оператор 'или'.

Observable<{count:number, next:string, previous:string, results: any[]}> |  Observable<any>
...