Czytam Routing i nawigację w Angular. Operator first() z rxjs nie działa i pojawia się błąd.

Oto moja usługa:

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

Oto mój bohater:

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

Oto moi pozorowani bohaterowie:

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' }
];

A oto mój błąd:

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

Chcę tylko Bohatera z moim zamierzonym identyfikatorem; jak mogę to zrobić?

0
Mohsen 1 kwiecień 2020, 15:49

4 odpowiedzi

Najlepsza odpowiedź

Powodem jest to, że używasz funkcji of zamiast from do tworzenia Observable zwracanej przez metodę getHeroes().

Jeśli zmienisz swój kod w ten sposób, nie otrzymasz więcej błędu kompilacji

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

Dzięki tej zmianie getHeroes() emituje strumień Hero s, a zatem funkcja predykatu, którą przekazujesz do first, otrzymuje tylko 1 Hero w tym samym czasie, a nie tablicę {{ X4}} s.

Jeśli chcesz zachować oryginalną wersję getHeroes(), musisz zmienić getHero() w ten sposób

getHero(id: string): Observable<Hero> {
  return getHeroes().pipe(
    map(heroes => heroes.find(hero => hero.id === +id))
  );
}
2
Picci 1 kwiecień 2020, 13:02

Myślę, że zwracasz Observable<Hero[]> i mówisz, że ta funkcja powinna zwrócić Observable<Hero>. Użyłbym map zamiast 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)),
    );
  }
1
AliF50 1 kwiecień 2020, 13:01

Typ twojego strumienia to Observable<Hero[]>, więc otrzymujesz wszystkich bohaterów jako tablicę w operatorze first.

Aby przekonwertować taki strumień na Observable<Hero> i otrzymać jednego bohatera na raz w operatorze first, możesz użyć operatora mergeAll.

    return this.getHeroes().pipe(
      mergeAll(),
      first(hero => hero.id === +id)
    );
0
kvetis 1 kwiecień 2020, 13:00

Musisz przekonwertować swoją tablicę Heroes używając from zamiast of.

Lubię to:

  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 przesyła strumieniowo wartości tablicy jedna po drugiej, podczas gdy of emituje całą tablicę naraz.

0
Baboo_ 1 kwiecień 2020, 13:02