Home > front end >  rxjs Error complaining about incompatible types
rxjs Error complaining about incompatible types

Time:10-27

follow on to SO 69670747

I have read a fair amount since getting some coaching in that SO. I am now down to an issue where TS is complaining about incompatible types. I am not seeing my mistake.

Note : I try to develop code so that the max amount is identical from source to source. One technique is to call the 'main' TYPE 'item' ( in this case... the main item type is ProjRev).
SO here , any reference to 'item' will be pointing to a ProjRev object (except for of course ProjectSvc.GetItemById) That seemed to cause confusion in the last SO , thought I would at least clarify...

import { Component, OnInit,  ElementRef, ViewChild } from '@angular/core';
import { Location } from '@angular/common';
import { ChangeDetectorRef } from '@angular/core';
  import { Observable,forkJoin, combineLatest } from 'rxjs';
import { distinctUntilKeyChanged, pluck
      , switchMap ,tap} from 'rxjs/operators';
import { ActivatedRoute } from '@angular/router';

import { Project } from '../project';
import { ProjectRev} from '../project-rev';
import { ProjectService } from '../services/project.service';
import { ProjectRevService } from '../services/project-rev.service';

 

interface  VM{
    projectRev : ProjectRev;
    project : Project;
}

@Component({
  selector: 'app-project-rev-detail',
  templateUrl: './project-rev-detail.component.html',
  styleUrls: ['./project-rev-detail.component.css']
})
export class ProjectRevDetailComponent implements OnInit  {
   private projectRevId$ : Observable<string>;
   private myItem$ : Observable<ProjectRev>;
   private myProject$ : Observable<Project>;


   public vm$ : Observable<VM>   ;
   

  constructor( private projrevSvc : ProjectRevService
          , private projectSvc : ProjectService
          ,private location: Location
          ,private activatedRoute: ActivatedRoute
       ) {

       }

  ngOnInit(): void {
    this.projectRevId$ = this.activatedRoute.params.pipe(
      pluck('id')
      ,tap( id => {  console.log('pRevId',id);})
    );

    this.myItem$ = this.projectRevId$.pipe(
      tap( item => {  console.log('inside projrev pipe',item);})
      ,   switchMap( (itemId : string) => this.projrevSvc.getItemById(  itemId   ))
      , tap( item => console.log('rev retrieved',item))
    );

    this.myProject$ = this.myItem$.pipe(
      tap( (prev : ProjectRev) =>{  console.log('inside getProj pipe');})
      ,distinctUntilKeyChanged('ProjectId')
      ,switchMap((item) => this.projectSvc.getItemById(item.ProjectId))
      , tap( item => console.log('proj retrieved',item))

    );

     this.vm$   = combineLatest(

      this.myItem$,
      this.myProject$
   ).subscribe(([ projRev , project]) => {
    this.myItem$ =projRev;
    this.myProject$ = project;
});

the error message is

   ERROR in src/app/projects/project-rev-detail/project-rev-detail.component.ts(76,5): error TS2740: Type 'Subscription' is missing the following properties from type 'Observable<VM>': _isScalar, source, operator, lift, and 114 more.
    src/app/projects/project-rev-detail/project-rev-detail.component.ts(81,9): error TS2740: Type 'ProjectRev' is missing the following properties from type 'Observable<ProjectRev>': _isScalar, source, operator, lift, and 114 more.
    src/app/projects/project-rev-detail/project-rev-detail.component.ts(82,9): error TS2740: Type 'Project' is missing the following properties from type 'Observable<Project>': _isScalar, source, operator, lift, and 114 more.

the service function that is being called is here... this is working as evidenced by my log listing

 getItemById(id: string): Observable< ProjectRev> {
     console.log('inside proj rev getItemByid..');
       const url = `${this.serviceUrl}/${id}`;
       return this.http.get< ProjectRev>(url, httpOptions)
           .pipe(
             catchError(err =>
               this.handleError(`getItemById=${id}`, err))
       );

   }

I have tried changing the VM interface to be observables and not observables. I have done all the permutations changing the interface and the combineLatest parm signature I am pretty sure this is where my trouble lies.

Question : There are no subscribes when I am initializing the observables in ngOnit(); I took this patter from an SO answer. Should there be subscribes? I have previously made the mistake of not subscribing...is it not necessary here?

The VM pattern is not necessary. It was suggested in an SO answer. I definitely see the advantage of wrapping the whole UI in 1 ngIf...But only if i can make it work. Is there a name for this pattern I can google? Anyone have a good example?

CodePudding user response:

Consider this:

public count : number;
initCount(){
  this.count = "Hello!";
}

Expected Error: Type 'string' is not assignable to type 'number'

That's because I first say count is a number, but then assign a string to it. How to fix this depends on the intention. Given how count is named, once might assume that assigning it a string was the mistake.


On to your code :)

public vm$: Observable<VM>;
ngOnInit(){
  this.vm$ = someObservable.subscribe(someLambda);
}

Here you're trying to assign a subscription to an observable. It's roughly the same error as above, but TypeScript will try to do duck-typing (look at the object properties and see if they match). Subscriptions and observables don't overlap.

That's what your error message is telling you.

How to fix this? The best way/ idiomatic way is hard to tell from what you've written here, but here's one way the types might align again.

this.vm$ = combineLatest(
  this.myItem$,
  this.myProject$
).pipe(
  map(([projectRev, project]) => ({
    projectRev,
    project
  }))
);

this.vm$.subscribe(({projectRev, project}) => {
  this.myItem$ = projectRev;
  this.myProject$ = project;
});

CodePudding user response:

public vm$:Observable<VM> typed as an Observable, but it's being assigned the return value of combineLatest subscribe, which would be of type Subscription. This is the mismatch

It's similar with the results of the combineLatest - also typed (and it appears assigned) incorrectly. VSCode, or any other IDE, would usually alert you to these mistakes

this.myItem$ =projRev;
this.myProject$ = project;
  • Related