TyForHelpDude TyForHelpDude - 12 days ago 7
TypeScript Question

return multiple types of Observable within Typescript

I have a method that returns either an object or an array of same objects based of request url. logic is simple;

myservice.service.ts:

private _url_User = "https://api.github.com/users/dummyuser";
constructor(private _http: Http){}

getUsers(followers?: boolean): Observable<User | User[]>{
this._url_User += followers?"/followers":"";//if followers equals true edit url, this returns array of same user object
return this._http.get(this._url_User).map(res=>res.json());
}


mycomponent.component.ts:

import { Component,OnInit } from '@angular/core';
import {Auth} from '../../services/auth.service';
import {CommentService} from '../../services/comment.service';
import {User} from '../../infrastructure/user';

@Component({
moduleId:module.id,
selector: 'app-comment',
templateUrl: '../../templates/comment.component.html'
})

export class CommentComponent implements OnInit{
user:User;
followers:User[];
constructor(private auth: Auth, private commentService: CommentService){
}
ngOnInit(){
this.commentService.getUsers().subscribe(d=>{ this.user=d[0]; console.log(this.user.email)});
this.commentService.getUsers(true).subscribe(d=>{this.followers=d; console.log(this.followers[0].email)});
}
}


and here is the error message I couldnt handle;
enter image description here

Answer

In general what I'd suggest doing is actually splitting this into two methods, rather than using a boolean flag. That'll be simpler and clearer all round, and will also solve your typing problem here for free.

If you really don't want to do that though, then you'll want to add a function overload to your method. With these, you can tell TypeScript that this function always returns a single user with the flag set to false, or many users if the flag is set to true, and you'll get the behaviour you're looking for.

An overload for this function will look something like this:

getUsers(): Observable<User>;
getUsers(followers: false): Observable<User>;
getUsers(followers: true): Observable<User[]>;
getUsers(followers?: boolean): Observable<User | User[]>{
    this._url_User += followers?"/followers":"";
    return this._http.get(this._url_User).map(res=>res.json());
}

I've put together a working example in the playground, if you want to get see exactly what all this looks like.

Note that this does preserve potential ambiguity where it still exists. I.e. if you call getUsers with a boolean and at compile time TypeScript doesn't know whether that's true or false, it'll still return Observable<User | User[]>. You'll have to use either type assertions or a type guard to get the correct type out - check out the Type Guards and Differentiating Types section in the handbook if you're not familiar with that stuff.