ngrx/effects 类型推断错误

ngrx/effects type inference error

我正在尝试使用效果实现身份验证功能。这些是相关的类

// auth.actions.ts

import { Action } from '@ngrx/store';
import { AuthVM, ParamsVM } from '../models';
import { Credential } from '../interfaces';

export const FETCH_AUTH_INFO = 'FETCH_AUTH_INFO';
export const AUTHENTICATE_WITHOUT_CREDENTIALS = 'AUTHENTICATE_WITHOUT_CREDENTIALS';

export class FetchAuthInfo implements Action {
  readonly type = FETCH_AUTH_INFO;

  constructor(public payload = undefined) { }
}

export class AuthenticateWithoutCredentials implements Action {
  readonly type = AUTHENTICATE_WITHOUT_CREDENTIALS;

  constructor(public payload: ParamsVM = undefined) { }
}

export type AuthActions =   FetchAuthInfo | AuthenticateWithoutCredentials;

#

// auth.effects.ts

import { Injectable } from "@angular/core";
import { Actions, Effect } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { Action } from '@ngrx/store';
import * as fromAuthActions from './auth.actions';
import { Storage } from '@ionic/storage';
import { fromPromise } from "rxjs/observable/fromPromise";
import { AuthVM, ParamsVM } from '../models';
import { of } from 'rxjs/observable/of';
import { AuthInfoFetched, AuthenticateWithoutCredentials} from './auth.actions';


@Injectable()
export class AuthEffects {

  constructor(
    private actions$: Actions, 
    private storage: Storage
  ) { }

  @Effect() fetchAuthInfo$: Observable<Action> = this.actions$
    .ofType(fromAuthActions.FETCH_AUTH_INFO)
    .mergeMap(() => fromPromise(this.storage.get('authInfo')))
    .mergeMap((data: AuthVM) => {
      if (data) {
        return of(new AuthInfoFetched(data));
      } else {
        return of(new AuthenticateWithoutCredentials());
      }
    });

}

我收到此错误:

The type argument for type parameter 'R' cannot be inferred from the usage. Consider specifying the type
            arguments explicitly. Type argument candidate 'AuthInfoFetched' is not a valid type argument because it is
            not a supertype of candidate 'AuthenticateWithoutCredentials'. Types of property 'type' are incompatible.
            Type '"AUTHENTICATE_WITHOUT_CREDENTIALS"' is not assignable to type '"AUTH_INFO_FETCHED"'.

据我所知,应该在运算符链的末尾返回一个 Action Observable。我不明白为什么我会收到错误消息,因为 AuthInfoFetchedAuthenticateWithoutCredentials 都实现了 Action 接口。

如果有用的话,这就是package.json文件

{
  "name": "app",
  "version": "0.0.1",
  "author": "Ionic Framework",
  "homepage": "http://ionicframework.com/",
  "private": true,
  "scripts": {
    "clean": "ionic-app-scripts clean",
    "build": "ionic-app-scripts build",
    "lint": "ionic-app-scripts lint",
    "ionic:build": "ionic-app-scripts build",
    "ionic:serve": "ionic-app-scripts serve"
  },
  "dependencies": {
    "@angular/common": "^4.4.6",
    "@angular/compiler": "^4.4.6",
    "@angular/compiler-cli": "^4.4.6",
    "@angular/core": "^4.4.6",
    "@angular/forms": "^4.4.6",
    "@angular/http": "^4.4.6",
    "@angular/platform-browser": "^4.4.6",
    "@angular/platform-browser-dynamic": "^4.4.6",
    "@ionic-native/admob-free": "^4.4.2",
    "@ionic-native/core": "3.12.1",
    "@ionic-native/splash-screen": "3.12.1",
    "@ionic-native/status-bar": "3.12.1",
    "@ionic/app-scripts": "2.1.3",
    "@ionic/storage": "2.0.1",
    "@ngrx/effects": "^4.1.1",
    "@ngrx/store": "^4.1.1",
    "@ngrx/store-devtools": "^4.1.1",
    "body-parser": "^1.18.2",
    "cordova-admob-sdk": "^0.11.1",
    "cordova-android": "^6.4.0",
    "cordova-plugin-admob-free": "^0.11.0",
    "cordova-plugin-console": "^1.1.0",
    "cordova-plugin-device": "^1.1.7",
    "cordova-plugin-splashscreen": "^4.1.0",
    "cordova-plugin-statusbar": "^2.3.0",
    "cordova-plugin-whitelist": "^1.3.3",
    "cordova-promise-polyfill": "0.0.2",
    "cordova-sqlite-storage": "^2.1.2",
    "cors": "^2.8.4",
    "express": "^4.16.2",
    "ionic-angular": "3.6.0",
    "ionic-plugin-keyboard": "^2.2.1",
    "ionicons": "3.0.0",
    "morgan": "^1.9.0",
    "rxjs": "5.4.3",
    "sw-toolbox": "3.6.0",
    "typescript": "2.3.4",
    "zone.js": "0.8.12"
  },
  "devDependencies": {
    "ionic": "3.19.1"
  },
  "description": "An Ionic project",
  "cordova": {
    "plugins": {
      "cordova-sqlite-storage": {},
      "cordova-plugin-console": {},
      "cordova-plugin-device": {},
      "cordova-plugin-splashscreen": {},
      "cordova-plugin-statusbar": {},
      "cordova-plugin-whitelist": {},
      "ionic-plugin-keyboard": {},
      "cordova-plugin-admob-free": {}
    },
    "platforms": [
      "android"
    ]
  }
}

如有任何帮助,我们将不胜感激。

在效果中,您使用 if/else 返回两种不同类型的操作,因此无法推断效果的类型。您可以使用 rxjs if 运算符或使用临时变量。注意 ngrx 现在使用带有 rxjs 6

的管道

这是显示不同方式的代码

  //one way
  @Effect() fetchAuthInfo$: Observable<Action> = this.actions$
    .ofType(fromAuthActions.FETCH_AUTH_INFO)
    .map(() => fromPromise(this.storage.get('authInfo')))
    .switchMap((data: AuthVM) => {
      let result;
      if (data) {
        result = of(new AuthInfoFetched(data));
      } else {
        result = of(new AuthenticateWithoutCredentials());
      }
      return result;
   });

   //second way 
   @Effect() fetchAuthInfo$: Observable<Action> = this.actions$
    .ofType(fromAuthActions.FETCH_AUTH_INFO)
    .map(() => fromPromise(this.storage.get('authInfo')))
    .switchMap((data: AuthVM) => Observable.if(() => data,
        of(new AuthInfoFetched(data)),
        of(new AuthenticateWithoutCredentials())
        )
    );

    //the new effect way in ngrx
     @Effect() fetchAuthInfo$ = this.actions$.pipe(
               ofType(fromAuthActions.FETCH_AUTH_INFO),
               map(() => fromPromise(this.storage.get('authInfo'))),
               switchMap((data: AuthVM) => iif(() => data,
                          of(new AuthInfoFetched(data)),
                          of(new AuthenticateWithoutCredentials()))
              )
      );

我还可以将返回值类型转换为 "Action" 类型

@Effect() fetchAuthInfo$: Observable<Action> = this.actions$
.ofType(FETCH_AUTH_INFO)
.mergeMap(() => fromPromise(this.storage.get('authInfo')))
.mergeMap((data: AuthVM) => {
  if (data) {
    return of(<Action>new AuthInfoFetched(data));
  } else {
    return of(<Action>new AuthenticateWithoutCredentials());
  }
});