Clay Smith Clay Smith - 2 days ago 5
TypeScript Question

Angular 2 Typescript: domain() is not a function

I have an article class as defined like so:

export class Article {
id : number;
isanon : boolean;
title: string;
link: string;
text: string;
subverse : string;
userID : string;
votes: number;

constructor(title: string, link: string, subverse : string, text : string, userID : string, votes?: number) {
this.title = title;
this.link = link;
this.text = text;
this.subverse = subverse;
this.userID = userID;
this.votes = votes || 0;
}

log() : void{
console.log("Title: " + this.title + " Link: " + this.link + " subverse: " + this.subverse);
}

domain(): string {
try {
const link: string = this.link.split('//')[1];
return link.split('/')[0];
} catch (err) {
return null;
}
}

voteUp(): void {
this.votes += 1;
}

voteDown(): void {
this.votes -= 1;
}


}


and I get the articles from the database using an observable service

export class HomeComponent implements OnInit {
articles : Article[];


and...

this.service.GetArticles(this.subverseStr).subscribe( (data)=>{
this.articles = <Article[]>data;
});


However, in my HTML template it doesn't recognize the domain() or any other TS functions.

<div class="meta">({{ article.domain() }})</div>


When the page is loaded, I get error:

core.umd.js:2837 EXCEPTION: Error in app/article/article.component.html:15:20 caused by: self.context.article.domain is not a function


It does recognize it as a function if I hard code my articles[] and it does recognize variable members. Any idea what is going on? Thanks.

Answer

GetArticles returns parsed JSON, it is a plain object from res.json(), not an array of instances of Article. So it can't have domain method.

<Article[]>data tricked typing system, so Typescript believes that it it is Article[] and doesn't warn on type mismatch.

It depends on what exactly is returned from server, should be something like

GetArticles(subverse : string) : Observable<Article[]>
{
    return this.http.get(...)
    .map(res => {
      let data: any = res.json();
      let dataArr: any[] = Object.values(data);

      return dataArr.map(({ title, link, ... }) => {
        return new Article(title, link, ...);
      });
    })
    .catch(this.handleError);

}

I would suggest to move properties that are shared by Article and JSON response and (title, link, ...) to common TypeScript interface, this can make types tighter.

Comments