1

I have code that works fine when "noImplicitAny": false.

import ...;

@Injectable()
export class HeroService {
  private _cachedHeroes: Observable<Hero[]>; 
  private _init: boolean;
  private _heroesObserver: Observer<Hero[]>;
  private _heroObserver: Observer<Hero>;
  heroes$: Observable<Hero[]>; 
  hero$:   Observable<Hero>; 
  public _dataStore: { heroes: Hero[], hero: Hero };

  constructor (private http: Http) {
        this._init = true;
        this._dataStore = { heroes: [], hero: {_id: null, name: null} };
        this.heroes$ = new Observable((observer: any) =>  this._heroesObserver = observer).share();//.publishReplay(1).refCount();
        this.hero$   = new Observable((observer: any) =>  this._heroObserver = observer).share();
        this._baseUrl = 'http://localhost:8081/api/hero/';  
  }

  loadHero1(id: number) {
      this.hero$ = this._cachedHeroes.map(heroes => heroes.find(hero => {hero._id === id;})) 
                                     .catch(handleError)
                                     .subscribe( data => {  
                                                            this._dataStore.hero = data;
                                                            this._heroObserver.next(this._dataStore.hero);
                                                         },  
                                                  error => handleError('Could not load hero.')
                                               );
  }
  .......
}        

Since I want to make it type safe, I changed the tsconfig.json to "noImplicitAny": true.

Then I got the following error

[0] services/hero.service.ts(58,7): error TS2322: Type 'Subscription' is not assignable to type 'Observable<Hero>'.
[0]   Property '_isScalar' is missing in type 'Subscription'.
[1] [BS] File changed: dist\services\hero.js
[1] [BS] File changed: dist\services\common.js
[0] services/hero.service.ts(58,65): error TS2345: Argument of type '(hero: Hero) => void' is not assignable to parameter of type '(value: Hero, index: number, obj: Hero[]) => boolean'.
[0]   Type 'void' is not assignable to type 'boolean'.

Here are my questions

  1. How can I cast this._cachedHeroes.map().subscribe() from type Subscription to type Observable to resolve TS2322 error? I have tried <Observable<Hero[]>>.this._cachedHeroes.... but it did not work.
  2. How can I define the type for the argument to TypeScript arrow function to resolve TS2345 error? I have tried heroes.find( (hero: Hero) => {hero._id === id;}) but it didn't work.
  3. How can I change the explicit any to an Observer type in the below code?

    this.hero$ = new Observable((observer: any) => this._heroObserver = observer).share();

Any advice is appreciated.

1
  • Can you mark the hero.service.ts(58,65)? Commented May 2, 2016 at 8:20

2 Answers 2

2

With the help of @Günter Zöchbauer, I got this thing straighten out. So adding return statement will resolve the type mismatch. Here is the modified code that passed the compiler check.

  loadHero1(id: number) {
      this.hero$ = this._cachedHeroes.map(heroes => heroes.find(hero => { return hero._id === id; } )) 
                                     .catch(handleError)
                                     .map( (data : Hero) => {  
                                                            this._dataStore.hero = data;
                                                            this._heroObserver.next(this._dataStore.hero);
                                                            return data;
                                                         } 
                                                  //error => handleError('Could not load hero.')
                                               );
  }
Sign up to request clarification or add additional context in comments.

Comments

1

subscribe() returns a Subscription, not an Observable

If you change subscribe() to map() it should work

  loadHero1(id: number) {
    this.hero$ = this._cachedHeroes
    .map(heroes => heroes.find(hero => {hero._id === id;})) 
    .catch(handleError)
    .map( data => {  
      this._dataStore.hero = data;
      this._heroObserver.next(this._dataStore.hero);
    });
  }

or alternatively change

heroes$: Observable<Hero[]>; 

to

heroes$: Subscription;

but I don't think that is not the intention of your code.

7 Comments

thanks for the quick response. will the second .map() serve the same purpose of subscript() method? And I just added a third question:) Will try your answer really quick.
No they have a different purpose. subscribe() makes the observable execute while map() doesn't. The Subscription returned by subscribe() allows you to cancel the subscription with subscr.unsubscribe(). If you want to receive data from an observable (like the code in my answer) you need to subscribe first like hero$.subscribe() or <div>{{hero$ | async}}</div>
I change the subscribe() to map() and got a different error: [0] services/hero.service.ts(58,7): error TS2322: Type 'Observable<void>' is not assignable to type 'Observable<Hero>'. [0] Type 'void' is not assignable to type 'Hero'. any idea?
I don't know TS generics (I'm only using Dart myself). You can try this._dataStore.hero = <Observable<Hero>>data;
I tried. it will give a new error. I can use (data: Hero) which doesn't give error but it won't resolve the [0] Type 'void' is not assignable to type 'Hero'.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.