0

In my Angular app, I'm getting this error when I try to compile:

Type 'Observable<Promise<void>>' is not assignable to type 'Observable<AuthResponseData>'. Type 'Promise' is missing the following properties from type 'AuthResponseData': kind, idToken, email, refreshToken, and 2 more

Here is the AuthResponseData interface:

export interface AuthResponseData {
  kind: string;
  idToken: string;
  email: string;
  refreshToken: string;
  localId: string;
  expiresIn: string;
  registered?: boolean;
}

Here is the login() method:

login() {

    let authObs: Observable<AuthResponseData>;

    authObs = this.authService.login(this.email, this.password);

    authObs.subscribe(
        resData => {
            console.log('Response Data:', resData);
            this.router.navigateByUrl('/home');
        },
        errRes => {
            console.log('Error Response:', errRes);
        });
}

And here is AuthService.login():

login(email: string, password: string) {
    return of(firebase.auth().signInWithEmailAndPassword(email, password)
      .then((user) => {
        console.log('Service User Value', user);
      }).catch((err) => {
        console.log('Service Error', err);
      }));
  }

Can someone please tell me what changes I need to make so that I'm assigning the correct type in the Observable?

user9847788
  • 2,135
  • 5
  • 31
  • 79
  • Mate the first answer here is pointing in the right direction. You are returning an observable of a promise of type void, meaning this line --> ```return of(firebase.auth().signInWithEmailAndPassword(email, password)``` dont do all the then and catch error stuff and convert your promise ```firebase.auth().signInWithEmailAndPassword(email, password)``` to an observable with the from instead of "of" keyword. Then subscribe properly. And I highly recommend to use the pipeable operators like catchError. – sagat May 04 '20 at 13:42

3 Answers3

1

This is one of the reasons why I don't prefer mixing promises and observables although it isn't a hack or a workaround.

If you still wish to convert the promise to an observable you could do it using RxJS from (RxJS v6.0.0+). From the docs:

Creates an Observable from an Array, an array-like object, a Promise, an iterable object, or an Observable-like object.

If a then or a catch method if provided to the promise, then the from operator will return an observable of the promise returned by the corresponding method instead of the source promise. It'd be better to remove them when converting.

Try the following

Service

import { from } from 'rxjs';

login(email: string, password: string) {
  return from(firebase.auth().signInWithEmailAndPassword(email, password));
}

Component

login() {
  let authObs: Observable<any>;  // <-- use 'any' instead of a specific type
  authObs = this.authService.login(this.email, this.password);
  authObs.subscribe(
    resData => {
      console.log('Response Data:', resData);
      this.router.navigateByUrl('/home');
    },
    errRes => {
      console.log('Error Response:', errRes);
    }
  );
}

Pre RxJS v6.0.0, please refer here.

ruth
  • 29,535
  • 4
  • 30
  • 57
  • 1
    are you sure to use then and catch and sorround it by from(promise.catch.error) like this? I think the catch and then clause arent needed, are they? regards – sagat May 04 '20 at 13:46
  • Thanks for the answer, but I've tried this code & same behaviour is occurring. I'm still navigating with invalid credentials – user9847788 May 04 '20 at 13:47
  • @sagat: You are correct, if we provide a `then` or a `catch` method, it will return the promise returned by them. – ruth May 04 '20 at 13:50
  • 1
    @user9847788 Please remove the `then` and `catch` method from the promise. I've updated the code. – ruth May 04 '20 at 13:51
0

This might solve your problem: Convert Promise to Observable

return firebase.auth().signInWithEmailAndPassword(email, password)
      .then((user) => {
        console.log('Service User Value', user);
      }).catch((err) => {
        console.log('Service Error', err);
      });

This code returns a promise. You're trying to assign your local Observable to the returned Promise. You first need to convert the promise to an observable with Observable.fromPromise.

  • Thanks for your answer. I've updated my question now with different code, & explained the issue. Can you please take a look? – user9847788 May 04 '20 at 13:29
0

It seems that your login method returns Promise not Observable, Promise has no subscribe method. To convert it to Observable you can use from operator. See that question for details: Convert Promise to Observable

EDIT:

First replace of with from to get Observable of response and not Observable of Promise. Then remove catch. It should look something like this:


 // in Component
 authObs = this.loginService('', '');

 authObs.subscribe(
      resData => {
        console.log('Response Data:', resData);

      },
      errRes => {
        console.log('Error Response:', errRes);
      });
  }

  // In service

  public login(email: string, password: string) {
    return from(firebase.auth().signInWithEmailAndPassword(email, password));

  }
  • Thanks for your answer. I've updated my question now with different code, & explained the issue. Can you please take a look? – user9847788 May 04 '20 at 13:30