Как я могу получить только один элемент, используя оператор Rx js First () - PullRequest
0 голосов
/ 01 апреля 2020

Я читаю Маршрутизация и навигация в Angular. first() оператор rxjs не работает, и я получаю ошибку.

Вот мой сервис:

import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { first } from 'rxjs/operators';
import { Hero } from './hero';
import { HEROES } from './mock-heroes';

@Injectable({
  providedIn: 'root',
})
export class HeroService {
  constructor() { }

  getHeroes(): Observable<Hero[]> {
    return of(HEROES);
  }

  getHero(id: string): Observable<Hero> {
    // With the following code I get error
    return this.getHeroes().pipe(
      first(hero => hero.id === +id)
    );
  }
}

Вот мой герой:

export interface Hero {
  id: number;
  name: string;
}

Вот мои смутные герои:

import { Hero } from './hero';

export const HEROES: Hero[] = [
  { id: 11, name: 'Dr Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

А вот и моя ошибка:

Type 'Observable<Hero | Hero[]>' is not assignable to type 'Observable<Hero>'. Type 'Hero | Hero[]' is not assignable to type 'Hero'. Type 'Hero[]' is missing the following properties from type 'Hero': id, name

Я хочу получить только Героя с моим предназначением Я бы; как я могу это сделать?

Ответы [ 4 ]

2 голосов
/ 01 апреля 2020

Причина в том, что вы используете функцию of вместо from для создания Observable, возвращаемого методом getHeroes().

Если вы измените свой код таким образом, вы больше не получите ошибка компиляции

getHeroes(): Observable<Hero> {  // the returned Observable emits Hero and not Hero[]
    return from(HEROES);   // from rather thanof
  }

  getHero(id: string): Observable<Hero> {
    return this.getHeroes().pipe(
      first(hero => hero.id === +id)
    );
  }

С этим изменением getHeroes() испускает поток Hero с, и поэтому функция предиката, которую вы передаете first, получает только 1 Hero в то время, а не массив из Hero с.

Если вы хотите сохранить исходную версию getHeroes(), вам нужно изменить getHero() следующим образом

getHero(id: string): Observable<Hero> {
  return getHeroes().pipe(
    map(heroes => heroes.find(hero => hero.id === +id))
  );
}
1 голос
/ 01 апреля 2020

Я думаю, что вы возвращаете Observable<Hero[]> и говорите, что эта функция должна возвращать Observable<Hero>. Я бы использовал map вместо first.

  import { map } from 'rxjs/operators';
......
  getHeroes(): Observable<Hero[]> {
    return of(HEROES);
  }

  getHero(id: string): Observable<Hero> {
    // With the following code I get error
    return this.getHeroes().pipe(
      map(heroes => heroes.find(hero => hero.id === +id)),
    );
  }
0 голосов
/ 01 апреля 2020

Вы должны преобразовать ваш массив Heroes, используя from вместо of.

Примерно так:

  getHeroes(): Observable<Hero[]> {
    return from(HEROES); // 'from' instead of 'of'.
  }

  getHero(id: string): Observable<Hero> {
    // With the following code I get error
    return this.getHeroes().pipe(
      first(hero => hero.id === +id)
    );
  }

from передает значения массива один за другим of испускает весь массив одновременно.

0 голосов
/ 01 апреля 2020

Тип вашего потока: Observable<Hero[]>, поэтому вы получаете всех героев в виде массива в операторе first.

Чтобы преобразовать такой поток в Observable<Hero>, вы получаете по одному герою за раз в оператор first, вы можете использовать оператор mergeAll.

    return this.getHeroes().pipe(
      mergeAll(),
      first(hero => hero.id === +id)
    );
...