En travaillant avec NgRX 8, mes collègues et moi sommes souvent confrontés à un message d'erreur étrange lors de la mise en œuvre des effets.
Le type «Observable <unknown>» ne peut pas être affecté au type «Observable <Action> | ((... args: any []) => Observable <Action>) '
Il est lié à des 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 capables de déstructurer 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 issues de commentaires et de réponses.
switchMap
Nous espérons toujours une astuce pour briser le message d'erreur.
9 Réponses :
En fait, vous devez traiter les actions créées par createAction
comme une fonction et l'appeler pour renvoyer l'objet action. Vérifiez cette desc . Donc, votre of(addCommentFailed)
doit être of(addCommentFailed())
.
Merci pour votre réponse, je sais que je dois exécuter la fonction mais cela ne cause pas l'erreur. Comme je l'ai mentionné dans les commentaires précédents, je ne cherche pas non plus une solution spécifique de la capture d'écran mais une instruction générale "déterminer rapidement ce qui ne va pas".
D'accord. Maintenant je comprends. Mais je crois qu'il ne peut y avoir aucune instruction générale. Je suggérerais d'utiliser les types de retour d'actions créés. Cette suggestion est basée sur cette spécification de test , vous pouvez voir un message d'erreur semblable étant asserted.Also vérifier cette
Je pense que c'est la bonne réponse. votre méthode catchError renvoie la fonction et non la valeur de la fonction. L'ajout de parenthèses à toutes les actions est requis dans NgRX 8.
J'ai également vu une erreur similaire.
Type 'Observable<unknown>' is not assignable to type 'Observable<Action> | ((...args: any[]) => Observable<Action>)'
Le moyen le plus rapide d'identifier ce qui a pu arriver est après |
séparateur. Le type est généralement Observable<{something}>
ou Observable<{something | another}>
. Il y a un |
séparateur et le deuxième élément n'est pas un observable. C'est peut-être le problème.
Si, par exemple, l'observable s'attend à avoir Observable<Action>
, mais qu'il existe un opérateur de canal, il renvoie autre chose que Observable<Action>
. Le type inattendu sera ajouté au type attendu dans le message d'erreur, car pour Observable, T n'existe pas dans ((...args: any[]) => Observable<Action>)
mon interprétation du message est
Le type interne d'un objet est inconnu, car nous ne savons pas à quel type s'attendre Observable<Action>
= Action
ou ((...args: any[]) => Observable<Action>)
= unknown
si le problème n'est pas immédiatement évident, je viens de commenter chaque opérateur de tube un par un et voir si l'erreur va bien. Si c'est le cas, maintenant je sais que cet opérateur est le problème, que je me concentre sur l'opérateur et trouve le problème.
Je suis intéressé de lire les réponses des autres utilisateurs. Ces deux voies m'indiquent toujours dans la bonne direction.
Salut @ mr.vea, merci pour votre réponse :) Je vais jeter un oeil à ceci aujourd'hui.
J'ai eu exactement le même problème et dans mon cas, c'était à cause d'accolades mal placées et d'une importation manquante.
Voici ce que j'ai fait pour le déboguer et le résoudre.
Divisez la fonction canalisable interne en fonctions individuelles. C'est la première étape pour moi en raison de la syntaxe complexe et des accolades auto-complétées 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
//login.service.ts performLogin() : Observable<boolean> { throw "Something went wrong"; //return of(true); }
Modifié ceci en 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 (comme dans l'exemple d'effets, cela devrait fonctionner). Il fallait donc l'inclure dans le bloc extérieur canalisable. 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 effectue les opérations suivantes (lancer une erreur ou renvoyer Observable de true)
performLogin$ = createEffect(() => this.actions$.pipe( ofType(performLogin), mergeMap(() => this.loginService.performLogin().pipe( map(() => loginSuccess()) ))) );
J'espère que cela t'aides.
Bonjour, merci pour votre réponse, je vais tester votre stratégie aujourd'hui et vous le faire savoir :)
Version rapide
commenter createEffect(() =>
,
corriger les erreurs que votre IDE (VSCode) signale,
ajoutez createEffect(() =>
retour.
Alternative - la réécriture comme celle-ci fonctionne également
@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'] }))) )
Additionnel
Aucune erreur après avoir fait ce qui précède? La vérification de type fait son travail correctement et vous indique que vous devriez mapper sur une Observable<Action>
ou pour un effet purement secondaire en ajoutant le deuxième argument { dispatch: false }
(c'est-à-dire ne pas distribuer une action). Voir la documentation sur les effets NgRx
Réponse plus ancienne (l'utilisation de @Effect
est inutile et n'est pas obligatoire)
Le moyen le plus simple que j'ai trouvé pour déboguer est d'écrire de manière version 7 avec le décorateur @Effect
et une fois terminé, réécrire à l'aide de createEffect
.
Donc pour déboguer:
Type 'Go' is not assignable to type 'ObservableInput<any>'
ce qui donne l'erreur non utile d'écrire comme (ajouter un décorateur, supprimer createEffect(() =>
, supprimer le crochet final),
Cannot find name 'SwitchMap'
Maintenant nous obtenons une erreur
@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'] })) )
Suivi par
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'] })) ) )
Réparer cela donne
someEffect$ = createEffect(() => { return this.actions$.pipe( ... ) })
Maintenant, réécrivez en termes NgRx 8. Pas joli mais ça marche.
createEffect(() =>
fonctionne parfaitement, merci beaucoup!
@ngfelixl pas tout à fait parfaitement, si je mets mon projet dans un mode dactylographié plus strict ( "strict": true
dans tsconfig.json
) alors cette approche ne fonctionne pas toujours.
D'accord, mais je veux dire parfaitement comparé au problème d'origine.
J'ai eu ce problème à cause d'un opérateur d'importation manquant ici
// events.effects.ts import { Observable, of } from 'rxjs'; ...
Je l'ai corrigé en ajoutant cette ligne de code en haut
// 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 suis d'accord, cette erreur apparaît si l'un des opérateurs ou "constructeurs" observables n'est pas importé. Mais il apparaît également si les types ne correspondent pas et dans plusieurs autres cas. Merci beaucoup pour votre réponse et je pense qu'il y a quelqu'un qui s'intéresse à votre solution. :)
En cas de résolution de ce problème et en utilisant l'exemple officiel de ngrx 8.
ofType<ReturnType<typeof myAction>>
Une solution simple et rapide peut être de mettre "n'importe quel" type.
ofType<MySuperActions>
N'oubliez pas les importations pour les opérateurs rxjs, les observables.
En cas de traitement de la charge utile d'action - props, définissez un type d'action.
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) )) ) );
ou
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) )) ) );
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é:
import { Action } from '@ngrx/store'; ... switchMap((action) => { return action.cart.flatMap((cartItem: CartItem) : Action[] => { ...
J'ai donc reçu le même message d'erreur:
Le type «Observable <unknown>» ne peut pas être affecté au type «Observable <Action> | ((... args: any []) => Observable <Action>) '
Pour résoudre ce problème, je devais juste dire à TypeScript que ma fonction de mappage renvoyait un tableau d' Action
:
this.actions$.pipe( ofType(ActionType), switchMap((action) => { return action.cart.flatMap((cartItem: CartItem) => { if (x) { return [ ActionCreator1(params1), ActionCreator2(params2) ]; } else { return []; } } }) )
De plus, taper avec Action[]
est plus sûr qu'avec any
!
Dans mon cas, j'ai utilisé un opérateur lodash à l'intérieur de 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 lutté avec ce problème pendant un certain temps pour découvrir à la fin que le code VS importait automatiquement Observable
partir d'une bibliothèque au lieu de rxjs
J'espère que cela évitera à quelqu'un de se cogner la tête.
qu'est-ce que
addComment
?Quel est le type de
addCommentFailed
/of(addCommentFailed)
?Il n'est pas important de résoudre ce problème, mais d'obtenir en quelque sorte une méthode générale pour traiter cette erreur.
addComment
est le retour de la méthodecreateAction
et n'est probablement pas le problème. Les méthodes d'failed
et desuccess
sont également des actionscreateAction
createAction. L'failed
n'est pas le problème ici, bien que je n'exécute pas l'action ayant échoué en tant que fonction.Je l'ai recréé localement et je n'obtiens aucune erreur. Avez-vous vérifié si l'espace de travail de votre éditeur utilise la version dactylographiée des projets? Parfois, VSCode commence à utiliser la version TS installée globalement.
Dans le paramètre ofType, vous devez le passer en tant que $ {votre action} .type, si l'action est créée via
createAction
@KiraAG non je n'ai pas besoin de faire ça, ça marche avec d'autres effets comme celui-ci.
@ cyr-x c'est ce qui m'a aidé à résoudre un problème antérieur et ce que je fais régulièrement si rien ne résout les erreurs de type. Bon point.
De plus, la commande de
Reload typescript project
ou le redémarrage d'un éditeur aide parfois, surtout si d'énormes projets sont ouverts pendant une longue période. Mais je suppose que ce n'est pas le problème ici.Ouais désolé. C'était lors de la phase initiale de la sortie du V8, nous avons dû utiliser le paramètre de
type
.