Lanre Afeez
Lanre Afeez

Reputation: 31

The 'Object' type is assignable to very few other types. Did you mean to use the 'any' type instead?

I have a rather complex code have been on for two days, I am using the map operator from rxjs operator to bring the values of IUser from the IUser interface. But I keep getting this error:

Argument of type 'OperatorFunction<IUser, void>' is not assignable to parameter of type 'OperatorFunction<Object, void>'. The 'Object' type is assignable to very few other types. Did you mean to use the 'any' type instead? Type 'Object' is missing the following properties from type 'IUser': email, displayName, token.

Thanks in advance.

Account.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { IUser } from '../shared/models/user';

@Injectable({
  providedIn: 'root'
})
export class AccountService {
  baseUrl = environment.apiUrl;
  private currentUserSource = new BehaviorSubject<IUser>(null!);
  currentUser$ = this.currentUserSource.asObservable();

  constructor(private http: HttpClient, private router: Router) { }

  login(values: any) {
    return this.http.post(this.baseUrl + 'account/login', values).pipe(
      map((user: IUser) => {
        if (user) {
          localStorage.setItem('token', user.token);
          this.currentUserSource.next(user)
        }
      })
    );
  }

login.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

User.ts

export interface IUser  {
    email: string;
    displayName: string;
    token: string;
} 

Upvotes: 1

Views: 1134

Answers (1)

Yong Shun
Yong Shun

Reputation: 51350

From HttpClient post(),

Overload #14

post(url: string, body: any | null, options?: {
        headers?: HttpHeaders | {
            [header: string]: string | string[];
        };
        context?: HttpContext;
        observe?: 'body';
        params?: HttpParams | {
            [param: string]: string | number | boolean | ReadonlyArray<string | number | boolean>;
        };
        reportProgress?: boolean;
        responseType?: 'json';
        withCredentials?: boolean;
    }): Observable<Object>;

Without specify T for .post() [Overload #14], it will return Observable<Object> value.

Overload #15

post<T>(url: string, body: any | null, options?: {
        headers?: HttpHeaders | {
            [header: string]: string | string[];
        };
        context?: HttpContext;
        observe?: 'body';
        params?: HttpParams | {
            [param: string]: string | number | boolean | ReadonlyArray<string | number | boolean>;
        };
        reportProgress?: boolean;
        responseType?: 'json';
        withCredentials?: boolean;
    }): Observable<T>;

From post() [Overload #15], you have to specify T for example post<T>(), so that it will return Observable<T> value.


Solution

Assumption: The response returned is IUser type.

  1. Specify T as IUser or any type to solve the error mentioned.

  2. As @Gunnar's comment, you have to use tap instead of map to perform the operation from the source observable without altering it.

    Using map must return a value for Observable.

login(values: any) {
  return this.http.post<IUser>(this.baseUrl + 'account/login', values).pipe(
    tap((user: IUser) => {
      if (user) {
        localStorage.setItem('token', user.token);
        this.currentUserSource.next(user);
      }
    })
  );
}

Upvotes: 1

Related Questions