Как вернуть CustomType, а не HttpEvent <CustomType>из вызова HTTP GET? - PullRequest
0 голосов
/ 27 февраля 2020

У меня есть служба, которая отправляет запрос и получает некоторых пользователей, как видно в консоли браузера:

HTTP event: 
{_embedded: {…}, _links: {…}, page: {…}}
_embedded: {userModelList: Array(4)}
_links: {self: {…}}
page: {size: 5, totalElements: 4, totalPages: 1, number: 0}
__proto__: Object
user.service.ts:49 HTTP response: 
{_embedded: {…}, _links: {…}, page: {…}}
_embedded: {userModelList: Array(4)}
_links: {self: {…}}
page: {size: 5, totalElements: 4, totalPages: 1, number: 0}
__proto__: Object

Регистратор в методе:

public getSome(searchTerm: string, sortFieldName: string, sortDirection: string, currentPage: number, pageSize: number): Observable<HateoasPageable> {
  let httpParams = new HttpParams()
  .set('page', currentPage.toString())
  .set('size', pageSize.toString());
  if (searchTerm) {
    httpParams = httpParams.append('searchTerm', searchTerm);
  }
  if (sortFieldName && sortDirection) {
    httpParams = httpParams.append('sort', sortFieldName + ',' + sortDirection);
  }
  return this.httpService.get<HateoasPageable>(this.usersUrl, httpParams)
  .pipe(
    tap((httpEvent: HttpEvent<HateoasPageable>) => console.log('HTTP event:', httpEvent)),
    map((httpEvent: HttpEvent<HateoasPageable>) => {
      return httpEvent as HttpResponse<HateoasPageable>;
    }),
    tap((httpResponse: HttpResponse<HateoasPageable>) => console.log('HTTP response:', httpResponse)),
    map((httpResponse: HttpResponse<HateoasPageable>) => {
      return httpResponse.body as HateoasPageable;
    })
  );
}

Он использует метод get:

export class HttpService {

    constructor(private httpClient: HttpClient) { }

    public get<T>(url: string, httpParams?: HttpParams, headers?: HttpHeaders): Observable<HttpEvent<T>> {
        let options = this.buildOptions(headers);
        options = this.addOptionParams(options, httpParams);
        return this.httpClient.get<T>(url, options);
    }

Но httpResponse.body возвращает неопределенное значение для компонента:

getUsers(searchTerm: string, sortFieldName: string, sortDirection: string, currentPageNumber: number): Observable<UsersApi> {
  return this.userService.getSome(searchTerm, sortFieldName, sortDirection, currentPageNumber, this.elementsPerPage)
    .pipe(
      map((hateoasPageable: HateoasPageable) => {
        console.log(hateoasPageable);
        return new UsersApi(
          hateoasPageable._embedded.userModelList as User[],
          hateoasPageable.page.pageNumber,
          hateoasPageable.page.pageSize,
          hateoasPageable.page.totalElements,
          hateoasPageable.page.totalPages
        );
      })
    );
}

Пользовательский класс:

export class HateoasPageable {

  _embedded: any = {};
  _link: any = {};
  page: HateoasPage = new HateoasPage(0, 0, 0, 0);

  constructor(_embedded: any, _link: any, page: HateoasPage) {
    this._embedded = _embedded;
    this._link = _link;
    this.page = page;
  }
}

Подписка на возвращаемое наблюдаемое выполняется далее в компоненте:

merge(this.updateEvent, this.searchTermEvent, this.sort.sortChange, this.paginator.page)
  .pipe(
    startWith({}),
    switchMap(() => {
      this.isLoadingResults = true;
      let pageIndex: number = 0;
      pageIndex = this.paginator.pageIndex;
      return this.getUsers(this.searchTerm, this.sort.active, this.sort.direction, pageIndex);
    }),
    map((usersApi: UsersApi) => {
      this.isLoadingResults = false;
      this.isRateLimitReached = false;
      this.currentPageNumber = usersApi.currentPageNumber;
      this.elementsPerPage = usersApi.elementsPerPage;
      this.totalElements = usersApi.totalElements;
      this.totalPages = usersApi.totalPages;
      return usersApi.users;
    }),
    catchError(() => {
      this.isLoadingResults = false;
      this.isRateLimitReached = true;
      return observableOf([]);
    })
  ).subscribe((users: User[]) => {
    this.dataSource.data = users;
  });

Журнал консоли показывает, что объект httpResponse выглядит как экземпляр HateoasPageable. Поэтому я надеялся изменить утверждение:

return httpResponse.body as HateoasPageable;

на утверждение:

return httpResponse as HateoasPageable;

Но затем компилятор жалуется на ошибку:

Conversion of type 'HttpResponse<HateoasPageable>' to type 'HateoasPageable' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

И если у меня просто есть утверждение:

return httpResponse;

, то компилятор жалуется на ошибку:

Type 'Observable<HttpResponse<HateoasPageable>>' is not assignable to type 'Observable<HateoasPageable>'.

Теперь я сталкиваюсь с этой проблемой, так как я активировал строгий режим:

  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,

Я под Angular 8.1.3

Ответы [ 2 ]

0 голосов
/ 27 февраля 2020

Я мог решить проблему после прочтения следующего решения , в котором объяснялось, что компилятор машинописного текста использовал неправильный метод get. Чтобы компилятор использовал правильный метод, решение проблемы заключалось в вводе параметров HTTP с помощью пользовательского класса. Поэтому я добавил класс:

class HttpOptions {
  headers?: HttpHeaders;
}

и использовал его как тип возвращаемого значения в методе:

private buildOptions(headers?: HttpHeaders): HttpOptions {
    const options = {
        headers: this.buildHeader(headers),
        responseType: 'json' as 'json'
    };
    return options;
}

Теперь метод get можно реализовать, просто возвращая пользовательский интерфейс, а не возвращая тип HttpEvent, например:

public get<T>(url: string, httpParams?: HttpParams, headers?: HttpHeaders): Observable<T> {
    let options = this.buildOptions(headers);
    options = this.addOptionParams(options, httpParams);
    return this.httpClient.get<T>(url, options);
}

Тогда метод обслуживания также упрощается:

public getSome(searchTerm: string, sortFieldName: string, sortDirection: string, currentPage: number, pageSize: number): Observable<HateoasPageable> {
  let httpParams = new HttpParams()
  .set('page', currentPage.toString())
  .set('size', pageSize.toString());
  if (searchTerm) {
    httpParams = httpParams.append('searchTerm', searchTerm);
  }
  if (sortFieldName && sortDirection) {
    httpParams = httpParams.append('sort', sortFieldName + ',' + sortDirection);
  }
  return this.httpService.get<HateoasPageable>(this.usersUrl, httpParams);
}
0 голосов
/ 27 февраля 2020

Чтобы отправить запрос GET и получить объект из тела ответа, вам просто нужно подписаться на метод get HttpClient:

constructor(private http: HttpClient) {
}
...
this.http.get(someUrl).subscribe(response => {
    console.log(response);  // here `response` is the object from the response body
});

Если у вас есть интерфейс для объекта ответа, тогда Вы можете использовать generi c версию get метода:

this.http.get<HateoasPageable>(someUrl).subscribe((data: HateoasPageable) => {
    console.log(data);  // here `data` is the object from the response body
});

Вы можете найти больше информации о Angular HttpClient в angular .io

...