Mientras trabajamos con NgRX 8, mis colegas y yo nos enfrentamos con frecuencia a un mensaje de error extraño al implementar los efectos.
El tipo 'Observable<desconocido>' no se puede asignar al tipo 'Observable<Acción> | ((...argumentos: cualquiera[]) => Observable<Acción>)'
Está relacionado con cuestiones de tipo. Es realmente molesto que el mensaje sea tan inespecífico y marque el efecto completo. Esto aparece con frecuencia y es realmente difícil de resolver.
Nos preguntamos si hay algo que podamos hacer para identificar rápidamente los problemas o si podemos desestructurar el mensaje de alguna manera. No estoy buscando una solución específica aquí, sino más bien un procedimiento de "cómo determinar rápidamente qué está mal".
¡Gracias y ánimo!
Es lo que hemos hecho hasta ahora y también ideas de comentarios y respuestas.
switchMapTodavía estamos esperando un truco para descomponer el mensaje de error.
Luché con este problema por un tiempo solo para descubrir al final que el código VS importaba automáticamente Observable de alguna biblioteca en lugar de rxjs
Espero que esto le ahorre a alguien golpes de cabeza innecesarios.
Tuve este error en mi proyecto y lo resolví agregando esta importación:
import { Observable, of as observableOf, of } from 'rxjs';Lo que me solucionó fue agregar Observable<Action> como el tipo de devolución para la función que se pasa a createEffect . Ex:
addComment$ = createEffect((): Observable<Action> => this.actions$.pipe( ... ), );Versión rápida
comentar createEffect(() => ,
corrija los errores que su IDE (VSCode) marca,
agregue createEffect(() => de nuevo.
Alternativa : reescribir como la siguiente también funciona
someEffect$ = createEffect(() => { return this.actions$.pipe( ... ) })Adicional
¿Todavía hay errores después de hacer lo anterior? La verificación de tipos está haciendo su trabajo correctamente y le dice que debe estar mapeando a un Observable<Action> o para un efecto puramente secundario agregando el segundo argumento { dispatch: false } (es decir, no despachando una acción). Consulte los documentos de efectos de NgRx
Respuesta anterior (usar @Effect no es necesario y no es obligatorio)
La forma más fácil que he encontrado para depurar es escribir en una versión 7 con el decorador @Effect y, una vez hecho, reescribir usando createEffect .
Así que para depurar:
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'] })) ) ) lo que da el error no útil escrito como (agregar decorador, eliminar createEffect(() => , eliminar corchete 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'] })) )Ahora obtenemos error
Cannot find name 'SwitchMap'Seguido por
Type 'Go' is not assignable to type 'ObservableInput<any>'Arreglar esto da
@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'] }))) )Ahora reescriba en términos de NgRx 8. No es bonito pero funciona.
En realidad, debe tratar las acciones creadas por createAction como una función y llamarla para devolver el objeto de acción. Compruebe esta descripción . Entonces su of(addCommentFailed) debería ser of(addCommentFailed()) .
He visto un error similar también.
Type 'Observable<unknown>' is not assignable to type 'Observable<Action> | ((...args: any[]) => Observable<Action>)' La forma más rápida de identificar lo que pudo haber sucedido es después de | separador. El tipo suele ser Observable<{something}> u Observable<{something | another}> . Hay un | separador y el segundo elemento no es un Observable. Este es quizás el problema.
Si, por ejemplo, el observable espera tener Observable<Action> , pero hay algún operador de tubería que devuelve algo distinto de Observable<Action> . El tipo inesperado se agregará al tipo esperado en el mensaje de error, porque para Observable, T no existe en ((...args: any[]) => Observable<Action>)
mi interpretación del mensaje es
Se desconoce el tipo interno de un objeto, porque no sabemos qué tipo esperar Observable<Action> = Action o ((...args: any[]) => Observable<Action>) = unknown
si el problema no es inmediatamente obvio, solo comento cada operador de tubería uno por uno y veo si el error desaparece. Si es así, ahora sé que este operador es el problema, entonces me enfoco en el operador y encuentro el problema.
Estoy interesado en leer las respuestas de otros usuarios. Esas dos vías siempre me señalan en la dirección correcta.
Tuve exactamente el mismo problema y, en mi caso, se debió a que los frenos estaban mal colocados y faltaba una importación.
Esto es lo que hice para depurarlo y resolverlo.
Dividir la función de canalización interna en funciones individuales. Este es el paso más importante para mí debido a la sintaxis compleja y las llaves autocompletadas de vscode, a veces existe una llave en el lugar equivocado y no es fácil de encontrar. Esto también resuelve casi todos los demás problemas (importaciones faltantes, tipos de devolución incorrectos, etc.) ya que el código para depurar es mucho más pequeño y vscode resalta este error individual de la subfunción.
esto es lo que tenia antes
performLogin$ = createEffect(() => this.actions$.pipe( ofType(performLogin), mergeMap(() => this.loginService.performLogin().pipe( map(() => loginSuccess()) ))) );Cambié esto a continuación
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())); }También una ventaja que obtuve de este enfoque es que el bloque catchError en la tubería interna no se activa (según el ejemplo de efectos, debería funcionar). Por lo tanto, tuvo que incluirlo en el bloque exterior apto para tuberías. Aquí se detecta el error y funciona como se esperaba. Pero aún averiguando por qué no funciona.
Solo para resumir, el servicio de inicio de sesión hace lo siguiente (lanzar error o devolver Observable de verdadero)
//login.service.ts performLogin() : Observable<boolean> { throw "Something went wrong"; //return of(true); }Espero que esto ayude.
En mi caso, utilicé un operador lodash dentro de uno de los operadores rxjs. Resultó que no tenía @types/lodash . Después npm i -D @types/lodash , mi problema se resolvió.
En caso de tratar este problema y usar el ejemplo oficial de 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) )) ) );La solución fácil y rápida puede ser poner "cualquier" tipo.
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) )) ) );No olvide las importaciones para operadores rxjs, observables.
En caso de tratar con carga útil de acción - props, defina un tipo de acción.
ofType<MySuperActions>o
ofType<ReturnType<typeof myAction>>Me encontré con un problema similar hoy (mismo mensaje de error) y fue porque TypeScript no pudo inferir correctamente el tipo de retorno de Array#flatMap . Supongo que será lo mismo para Array#map , RxJS#map o cualquier matriz que no se haya escrito explícitamente.
Aquí está el código que falló:
this.actions$.pipe( ofType(ActionType), switchMap((action) => { return action.cart.flatMap((cartItem: CartItem) => { if (x) { return [ ActionCreator1(params1), ActionCreator2(params2) ]; } else { return []; } } }) )Entonces recibí el mismo mensaje de error:
El tipo 'Observable<desconocido>' no se puede asignar al tipo 'Observable<Acción> | ((...argumentos: cualquiera[]) => Observable<Acción>)'
Para solucionarlo, solo tuve que decirle a TypeScript que mi función de mapeo devolvió una matriz de Action :
import { Action } from '@ngrx/store'; ... switchMap((action) => { return action.cart.flatMap((cartItem: CartItem) : Action[] => { ... Además, escribir con Action[] es más seguro que con any !
Tuve este problema debido a que faltaba el operador de importación 'de' aquí
// 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 }))) ) ) ) ); ...Lo arreglé agregando esta línea de código en la parte superior
// events.effects.ts import { Observable, of } from 'rxjs'; ...