如何修复错误 "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.
我收到一个错误,我无法理解原因。
我已经阅读了所有关于效果创建的内容,但仍然无法找出这个错误的原因。
我是 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.