Lucas David Ferrero
Lucas David Ferrero

Reputation: 1902

Cannot invoke an expression whose type lacks a call signature. Type 'UserModel' has no compatible call signatures

I'm getting a type error when I'm trying to set a property in my user.service.ts. This is how user.service looks like:

import { Injectable } from '@angular/core';
import { UserModel } from '../models/user.model';

@Injectable()
export class UserService {
  private _user: UserModel;
  constructor() {}

  get getUser(): UserModel {
    return this._user;
  }
  set setUser(user: UserModel) {
    this._user = user;
  }
}

And UserModel:

export class UserModel {
  constructor(public uid: string,
              public displayName: string,
              public email: string,
              public photoUrl: string,
              public providerId: string) {}
}

Finally this is the auth.service where I got the error.

import {Injectable} from '@angular/core';
import * as firebase from 'firebase';
import { AngularFireAuth } from 'angularfire2/auth';
import {Router} from '@angular/router';
import { UserModel } from '../models/user.model';
import { UserService } from './user.service';


@Injectable()
export class AuthService {
  private _token: string = null;

  // We use first login in app.module to check if is the first login. If it is we skip the refresh token method.
  private _firstLogin = false;
  constructor(private afAuth: AngularFireAuth,
              private router: Router,
              private userService: UserService) {}

  get isFirstLogin() {
    return this._firstLogin;
  }
  get getUserToken(): string{
    return this._token;
  }
  set setUserToken(tk: string) {
    this._token = tk;
  }
  // We define the Facebook provider and passing it to signin(). We do this for each provider that we want to integrate.
  signinWithFacebook(): Promise<any> {
    const fbProvider = new firebase.auth.FacebookAuthProvider();
    return this.signin(this.afAuth.auth.signInWithPopup(fbProvider));
  }

  // If this method get resolved then we redirect the user to the home page and get the token.
  // Besides, when this method execute the reject() we catch it in the login component and we handle the errors there.
  // This method can be reusable across multiple providers such Facebook, Twitter, Github , etc.
  signin(popupResult: Promise<any>): Promise<any> {
    return popupResult
      .then(
        (res) => {
          this._firstLogin = true;
          const user: firebase.User = res.user.toJSON();
          const credential = res.credential;
          this._token = credential.accessToken;

          // Initialising the user and passing to the user service's property (_user)
          // TODO fix: Solucionar error de la línea 51.
          const providedData = user.providerData[0];
          const buildedUser = new UserModel(providedData.uid, providedData.displayName,
            providedData.email, providedData.photoURL, providedData.providerId);
          this.userService.setUser(buildedUser); //HERE I GOT THE ERROR.

          console.log(this._token);
          console.log(user);
        }
      );
  }
}

I got the error when I'm trying to pass an UserModel from auth.service to user.service in this line of code: this.userService.setUser(buildedUser). I hope you get it and give me a solution and also tell me why is this happens. Regards!

Upvotes: 2

Views: 2162

Answers (1)

jcalz
jcalz

Reputation: 328453

Remove get and set from your methods in UserService:

@Injectable()
export class UserService {
  private _user: UserModel;
  constructor() {}

  getUser(): UserModel {
    return this._user;
  }
  setUser(user: UserModel) {
    this._user = user;
  }
}

You probably don't want to use a setter for setUser(). A setter would get called if you did something like this.userService.setUser = buildedUser. If you want to call it like this.userService.setUser(buildedUser) then setUser() is just a plain old method.

Likewise, when you get the user, you probably want to call const retrievedUser = this.userService.getUser(), not const retrievedUser = this.userService.getUser. The former is just a plain method, while the latter would be a getter.


If you really want to use getters and setters, you can keep get and set but maybe rename getUser and setUser to just user:

@Injectable()
export class UserService {
  private _user: UserModel;
  constructor() {}

  get user(): UserModel {
    return this._user;
  }
  set user(user: UserModel) {
    this._user = user;
  }
}

and then call this.userService.user = buildedUser or const retrievedUser = this.userService.user and your setter and getter will be called.

But the idea behind getters and setters is that callers see them as just property accesses whereas you can implement them as methods that do more than just getting and setting properties. If all you're doing is just getting and setting properties, you might as well just have a public property called user:

@Injectable()
export class UserService {
  public user: UserModel;
  constructor() {}
}

Which would still let you do this.userService.user = buildedUser or const retrievedUser = this.userService.user with less fuss.


Upvotes: 2

Related Questions