如何修复错误 "Type 'Observable<void | ({...}>' is not assignable to type 'EffectResult<Action>'"?

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

我收到一个错误,我无法理解原因。
我已经阅读了所有关于效果创建的内容,但仍然无法找出这个错误的原因。
我是 angular 的新手,尤其是 Ngrx,所以也许我没有看到明显的东西。
我创建了一个动作:

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 }>()
    );

其减速器:

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,
    }))
);

我要调用以登录用户的服务:

  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);
  }

最后是效果:

  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)))
          )
        )
      )
      
  );

在使用 map 而不是 switchMap 和 {dispatch: false} 之前一切正常,但当然没有派发新动作。 切换到 switchMap 并删除 {dispatch: false} 会产生错误:

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'.

有人可以帮助我吗?
编辑:我知道 switchMap 有一个 return 值。发送一个新动作 return 不是一个值吗?我也试过 return authLoginSuccess 但没办法。

我猜这是因为你没有return在你的 mergeMap 中添加任何东西。

因为您没有像这样使用 {}:map(serverAuthData => { ... return X})。您只能写一行,在本例中是您的 console.log("Converting data"); 并且 return 未定义。

所以你可以删除 console.log("Converting data"); 并让 authLoginSuccess 成为那个,或者你可以使用 { } 和 return 你想要的那个。

像这样:

您还可以从 import { Effect } from "@ngrx/effects";

导入效果器

并将createEffect写成装饰器。

  @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)))
      )
    )
  );

POST.
末尾的解决方案 为了更好地说明,我进一步简化了代码以使其更小:
操作:

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

减速器:

  on(authLoginSuccess, (state,{serverAuthData}) => (
    { ...state,
      isAuthenticated: true,
      utente: serverAuthData.Utente,
      accessToken: serverAuthData.AccessToken,
      refreshToken: serverAuthData.RefreshToken,
      erroMessage: "",
    }))
);

最后效果:

@Injectable()
export class AuthEffects {
  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) =>  authLoginSuccess({serverAuthData})),
            catchError((error: any) => of(this.authService.loginFailure(error))),
          )
        )
      )
  );

我仍然收到错误消息:

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

我不明白问题出在哪里。
我也尝试使用@effect 装饰器,但错误从设计转移到运行时。
编辑: 删除 CreateEffect 并使用 @Effect() 效果很好!!!

  //login$ = 
  //createEffect(() => 
  @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 =>  authLoginSuccess({serverAuthData})),
            catchError((error: any) => of(this.authService.loginFailure(error))),
          )
        )
      );
  //);

最终编辑: 我在 GitHub 上打开了一个错误,在那里我收到了错误的解释。

The return type of authService.loginFailure() method seems to be void. You must return an action instead.

It works with @Effect() because decorators are not type safe. So, you need to pass the action here:
catchError(error => of(loginFailure({ error }) /* <- action */)) Adding a return value solved the issue.
I suppose these are the quirks of functional programming. I got the error on this.Actions$.pipe, of course, and focused on the success part, and I didn't realize it was loginError being void. I'm still new to Angular and ngrx.