Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
999 views
in Technique[技术] by (71.8m points)

angular - How do I fix error "Type 'Observable<void | ({...}>' is not assignable to type 'EffectResult<Action>'"?

I am receiving an error I can't understand the cause.
I've read everything I could on effect creation, but still can't figure this error cause.
I'm new to angular and especially Ngrx, so maybe I don't see something obvious.
I've created an action:

export interface ServerAuthData{
  AccessToken: string;
  RefreshToken: string;
  Utente: Utente;
}
export interface AuthState {
  isAuthenticated: boolean;
  errorMessage: string;
  accessToken: string;
  refreshToken: string;
  utente: Utente;
}

    export const authLogin = createAction(
    '[Auth] Login',  
    props<{ username: string,password: string }>()
    );

its reducer:

const reducer = createReducer(
  initialState,
  on(authLogin, (state) => ({ ...state })),
  on(authLogout, (state) => (
    { ...state,
      isAuthenticated: false ,
      utente: null,
      accessToken: "",
      refreshToken: "",
    })),
  on(authLoginSuccess, (state,{authState}) => (
    { ...state,
      isAuthenticated: true,
      utente: authState.utente,
      accessToken: authState.accessToken,
      refreshToken: authState.refreshToken,
      erroMessage: authState.errorMessage,
    }))
);

the service I'm going to call to login the user:

  login(username: string,password: string) {
    var formData: any = new FormData();
    formData.append("username", username);
    formData.append("password", password);
    console.log("Chiamo il server");
    return this.http.post<ServerAuthData>(this.loginUrl, formData);
  }

and finally the effect:

  login$ = 
  createEffect(() =>
      this.actions$.pipe(
        ofType(authLogin),
        switchMap((action) =>
          this.authService.login(action.username,action.password).pipe(
            tap((serverAuthData) => console.log('Dopo login. Ricevuto:' + serverAuthData)),
            map((serverAuthData) =>  
              console.log("Converting data");
              authLoginSuccess({authState:{
                isAuthenticated: true,
                accessToken: serverAuthData.AccessToken,
                errorMessage: "",
                refreshToken : serverAuthData.RefreshToken,
                utente: serverAuthData.Utente,
              }}
              
              )),
            catchError((error: any) => of(this.authService.loginFailure(error)))
          )
        )
      )
      
  );

Everything worked before using map instead of switchMap,and with {dispatch: false} but of course no new action was dispatched. Switching to switchMap and removing {dispatch: false}has generate the error:

Type 'Observable<void | ({ authState: AuthState; } & TypedAction<"[Auth] LoginSuccess">)>' is not assignable to type 'EffectResult'.

Type 'Observable<void | ({ authState: AuthState; } & TypedAction<"[Auth] LoginSuccess">)>' is not assignable to type 'Observable'.

Type 'void | ({ authState: AuthState; } & TypedAction<"[Auth] LoginSuccess">)' is not assignable to type 'Action'.

Type 'void' is not assignable to type 'Action'.

Can someone help me?
EDIT: I understand that switchMap HAS to return a value. Doesn't dispatching a new action returns a value? I've also tried return authLoginSuccess but no way.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I guess it's because you are not returning anything in your mergeMap.

Because you didn't use {} like: map(serverAuthData => { ... return X}). you are allowed to write only one line which in this case is your console.log("Converting data"); and it returns undefined.

so you can remove console.log("Converting data"); and let the authLoginSuccess be the one or you can use { } and return the one you want.

like this:

you can also import Effect from import { Effect } from "@ngrx/effects";

and write createEffect as a decorator.

  @Effect()
  login$ = this.actions$.pipe(
    ofType(authLogin),
    switchMap(action =>
      this.authService.login(action.username, action.password).pipe(
        tap(serverAuthData =>
          console.log("Dopo login. Ricevuto:" + serverAuthData)
        ),
        map(serverAuthData => {
          console.log("Converting data");
          return authLoginSuccess({
            authState: {
              isAuthenticated: true,
              accessToken: serverAuthData.AccessToken,
              errorMessage: "",
              refreshToken: serverAuthData.RefreshToken,
              utente: serverAuthData.Utente
            }
          });
        }),
        catchError((error: any) => of(this.authService.loginFailure(error)))
      )
    )
  );

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...