web-dev-qa-db-fra.com

Effets NgRX 8 - Le type 'Observable <inconnu>' n'est pas assignable au type 'Observable <Action>'

En travaillant avec NgRX 8, mes collègues et moi sommes souvent confrontés à un étrange message d'erreur lors de la mise en œuvre des effets.

Le type "Observable <inconnu>" n'est pas attribuable au type "Observable <Action> | ((... args: any []) => Observable <Action>) '

Il est lié aux problèmes de type. C'est vraiment ennuyeux que le message soit si peu spécifique et qu'il marque l'effet complet. Cela apparaît fréquemment et est vraiment difficile à résoudre.

enter image description here

Nous nous demandons s'il y a quelque chose que nous pouvons faire pour identifier rapidement les problèmes ou si nous sommes en mesure de détruire le message d'une manière ou d'une autre. Je ne cherche pas ici une solution spécifique, mais plutôt une procédure "comment déterminer rapidement ce qui ne va pas".

Merci et bravo!

Collection de possibilités

C'est ce que nous avons fait jusqu'à présent et aussi des idées de commentaires et de réponses.

  • Dans la plupart des cas, ce n'est probablement pas un problème avec les actions
  • Il peut s'agir d'une mauvaise déstructuration du paramètre switchMap
  • L'un des opérateurs RxJS n'est pas importé
  • Des paramètres et une valeur de retour incorrects dans le service peuvent être la raison
  • Des types incohérents de service et d'action peuvent également être la raison
  • Si rien ne vous aide et que vous êtes sûr, il n'y a rien de mal: Recharger TypeScript

Nous espérons toujours une astuce pour décomposer le message d'erreur.

17
Felix Lemke

Version rapide
commenter createEffect(() =>,
corrige les erreurs signalées par votre IDE (VSCode),
ajoutez createEffect(() => en arrière.

Alternative - la réécriture comme celle-ci fonctionne également

someEffect$ = createEffect(() => {
  return this.actions$.pipe(
    ...
  )
})

Supplémentaire

Aucune erreur après avoir fait ce qui précède? La vérification de type fait son travail correctement et vous dit que vous devez mapper sur un Observable<Action> Ou pour un effet purement secondaire en ajoutant le deuxième argument { dispatch: false } (C'est-à-dire ne pas envoyer d'action). Voir les NgRx Effects Docs


Ancienne réponse (l'utilisation de @Effect N'est pas nécessaire et n'est pas requise)

Le moyen le plus simple que j'ai trouvé pour déboguer est d'écrire à la manière de la version 7 avec le décorateur @Effect Et une fois terminé de réécrire en utilisant createEffect.

Donc pour déboguer:

  navigateToDashboard$ = createEffect(() =>
    this.actions$.pipe(
      ofType(teamActions.CREATE_SUPERVISOR_GROUP_SUCCESS),
      map((action: teamActions.CreateSupervisorGroupSuccess) => action.payload),
      map((team: Team) => team.TeamID),
      SwitchMap(id => new routerActions.Go({ path: ['/team', id, 'populate'] }))
    )
  )

ce qui donne l'erreur non utile écrire comme (ajouter un décorateur, supprimer createEffect(() =>, supprimer le crochet final),

@Effect()
navigateToDashboard$ = this.actions$.pipe(
    ofType(teamActions.CREATE_SUPERVISOR_GROUP_SUCCESS),
    map((action: teamActions.CreateSupervisorGroupSuccess) => action.payload),
    map((team: Team) => team.TeamID),
    SwitchMap(id => new routerActions.Go({ path: ['/team', id, 'populate'] }))
)

Maintenant, nous obtenons une erreur

Cannot find name 'SwitchMap'

Suivi par

Type 'Go' is not assignable to type 'ObservableInput<any>'

La correction de cela donne

@Effect()
navigateToDashboard$ = this.actions$.pipe(
    ofType(teamActions.CREATE_SUPERVISOR_GROUP_SUCCESS),
    map((action: teamActions.CreateSupervisorGroupSuccess) => action.payload),
    map((team: Team) => team.TeamID),
    switchMap(id => of(new routerActions.Go({ path: ['/team', id, 'populate'] })))
)

Maintenant, réécrivez en termes NgRx 8. Pas joli mais ça marche.

29
Andrew Allen

J'ai eu exactement le même problème et dans mon cas, c'était à cause d'appareils orthopédiques mal placés et d'une importation manquante.

Voici ce que j'ai fait pour le déboguer et le résoudre.

Divisez la fonction intérieure de tuyau en fonctions individuelles. C'est la première étape pour moi en raison de la syntaxe complexe et des accolades de saisie automatique de vscode, parfois une accolade existe au mauvais endroit et ce n'est pas facile à trouver. Cela résout également presque tous les autres problèmes (importations manquantes, types de retour incorrects, etc.) car le code à déboguer est beaucoup plus petit et vscode met en évidence cette erreur individuelle de la sous-fonction.

C'est ce que j'avais avant

    performLogin$ = createEffect(() => 
       this.actions$.pipe(
           ofType(performLogin),
           mergeMap(() => this.loginService.performLogin().pipe(
               map(() => loginSuccess())
           )))
    );

Remplacé par ci-dessous

 performLogin$ = createEffect(() => 
       this.actions$.pipe(
           ofType(performLogin),
           mergeMap(() => this.performLogin()),
           catchError((error ) => { console.log("HELLO"); return EMPTY})
       )
    );

    performLogin() {
        return this.loginService.performLogin()
        .pipe(map(() => loginSuccess()));
    }

Un autre avantage que j'ai obtenu de cette approche est que le bloc catchError sur le tube interne ne se déclenche pas (selon l'exemple d'effets, cela devrait fonctionner). Il a donc fallu l'inclure dans le bloc externe de canalisation. Ici, l'erreur est détectée et fonctionne comme prévu. Mais toujours comprendre pourquoi cela ne fonctionne pas.

Pour résumer, le service de connexion fait ce qui suit (erreur de lancement ou retour Observable ou vrai)

//login.service.ts

performLogin() : Observable<boolean> {
        throw "Something went wrong";
        //return of(true);
    }

J'espère que cela t'aides.

4
sumanth shankar

En fait, vous devez traiter les actions créées par createAction comme une fonction et l'appeler pour renvoyer l'objet action. Vérifiez ceci desc . Votre of(addCommentFailed) doit donc être of(addCommentFailed()).

1
KiraAG

En cas de résolution de ce problème et d'utilisation de l'exemple officiel ngrx 8.

loadMovies$ = createEffect(() => this.actions$.pipe(
    ofType('[Movies Page] Load Movies'),
    mergeMap(() => this.moviesService.getAll()
      .pipe(
        map(movies => ({ type: '[Movies API] Movies Loaded Success', payload: movies })),
        catchError(() => EMPTY)
      ))
   )
);

Une solution simple et rapide peut être de mettre "n'importe quel" type.

loadMovies$: any = createEffect((): any => this.actions$.pipe(
    ofType('[Movies Page] Load Movies'),
    mergeMap(() => this.moviesService.getAll()
      .pipe(
        map(movies => ({ type: '[Movies API] Movies Loaded Success', payload: movies })),
        catchError(() => EMPTY)
      ))
   )
);

N'oubliez pas les importations pour les opérateurs rxjs, observables.

En cas de traitement des charges utiles - accessoires, définissez un type d'action.

ofType<MySuperActions>

ou

ofType<ReturnType<typeof myAction>>
1
apincik

J'ai rencontré ce problème en raison de l'import manquant de l'opérateur ici

// events.effects.ts
...

getEvents$: Observable<Action> = createEffect(
    () => this.actions$.pipe(
      ofType(EventsActions.getEvents),
      switchMap(action =>
        this.eventService.getEvents().pipe(
          map(events => EventsActions.getEventsSuccess({ events })),
          catchError(error => of(EventsActions.getEventsError({ error })))
        )
      )
    )
  );
...

Je l'ai corrigé en ajoutant cette ligne de code en haut

// events.effects.ts

import { Observable, of } from 'rxjs';

...
0
Milena

Dans mon cas, j'ai utilisé un opérateur lodash dans l'un des opérateurs rxjs. Il s'est avéré que je n'avais pas @types/lodash. Après npm i -D @types/lodash, mon problème a été résolu.

0
user2991036

J'ai rencontré un problème similaire aujourd'hui (même message d'erreur) et c'était parce que TypeScript ne pouvait pas déduire correctement le type de retour de Array#flatMap . Je suppose que ce sera la même chose pour Array#map , RxJS#map ou tout tableau qui n'a pas été explicitement tapé.

Voici le code qui s'est écrasé:

this.actions$.pipe(
    ofType(ActionType),
    switchMap((action) => {
        return action.cart.flatMap((cartItem: CartItem) => {
            if (x) {
                return [
                    ActionCreator1(params1),
                    ActionCreator2(params2)
                ];
            } else {
                return [];
            }
        }
    })
)

J'ai donc eu le même message d'erreur:

Le type "Observable <inconnu>" n'est pas attribuable au type "Observable <Action> | ((... args: any []) => Observable <Action>) '

Pour résoudre ce problème, je devais simplement dire à TypeScript que ma fonction de mappage avait renvoyé un tableau de Action:

import { Action } from '@ngrx/store';
...
    switchMap((action) => {
        return action.cart.flatMap((cartItem: CartItem) : Action[] => {
...

De plus, en tapant avec Action[] est plus sûr qu'avec any!

0
boehm_s