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.
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!
C'est ce que nous avons fait jusqu'à présent et aussi des idées de commentaires et de réponses.
switchMap
Nous espérons toujours une astuce pour décomposer le message d'erreur.
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.
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.
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())
.
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>>
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';
...
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.
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
!