0
votes

I'm new to ngrx and following a not that old tutorial but it seems the way "map", "ofType", "of" and "pipe" are used, have changed, so "map" and "of" are throwing errors

"map" error : Property 'map' does not exist on type 'OperatorFunction'.ts(2339)

and

"of" error:// Property 'of' does not exist on type 'typeof Observable'.ts(2339)

Here is the Action:

export class GetUser implements Action {
     readonly type = GET_USER;
     constructor(public payload?: any) { }
}

Hereis the Effect:

@Effect()
 getUser: Observable<Action> = this.actions.pipe(ofType(userActions.GET_USER)
      **.map**((action: userActions.GetUser) => action.payload)
      .switchMap(payload => this.afAuth.authState)
      .delay(2000)
      .map(authData => {
           if (authData) {
                const user = new User(authData.uid, authData.displayName);
                return new userActions.Authenticated(user);
           } else {
                return new userActions.NotAuthenticated();
           }
      }).catch(err => Observable.**of**(new userActions.AuthError()));
2

2 Answers

2
votes

Seems like this is using an older version of RxJS. Since version 6 (I believe), pipeable operators should be used. These are imported from 'rxjs/operators', e.g. import { map } from 'rxjs/operators';

@Effect()
 getUser: Observable<Action> = this.actions.pipe(ofType(userActions.GET_USER)
      ,map((action: userActions.GetUser) => action.payload)
      ,switchMap(payload => this.afAuth.authState)
      ,delay(2000)
      ,map(authData => {
           if (authData) {
                const user = new User(authData.uid, authData.displayName);
                return new userActions.Authenticated(user);
           } else {
                return new userActions.NotAuthenticated();
           }
      });

See the docs https://rxjs-dev.firebaseapp.com/guide/operators

1
votes

Yeah, they changed in RxJS v6, I think it was. Now many of them are considered "pipeable" operators meaning that they are passed into the pipe method as arguments instead of the chaining like you're doing here. Your code should look more like:

@Effect()
 getUser: Observable<Action> = this.actions.pipe(
     ofType(userActions.GET_USER),
     map((action: userActions.GetUser) => action.payload),
     switchMap(payload => this.afAuth.authState),
     debounceTime(2000),
     map(authData => {
           if (authData) {
                const user = new User(authData.uid, authData.displayName);
                return new userActions.Authenticated(user);
           } else {
                return new userActions.NotAuthenticated();
           }
      }),
      catch(err => of(new userActions.AuthError())
    )
 );

I'm not sure why the delay was in there, but it sounds like you want to pause for 2000 milliseconds before continuing so I replaced that method with debounceTime.

Also, if you're using VS Code, get the latest Angular Essentials extension and it will help you with the imports.

Methods like map and switchMap will be imported from rxjs/operators while creation methods like of will be imported from rxjs