Home > Enterprise >  Angular typescript response model and type error
Angular typescript response model and type error

Time:11-17

On a local MEAN stack app using NodeJS server, my endpoint response returns array os Post:

{
  "message": "Posts fetched successfully!",
  "posts": [
    {
     "_id": "618b22ff9e50776ed377c4eb",
     "title": "aaaaaaaaaaaaaa",
     "body": "xxxxxxxxxxxxx",
     "__v": 0
    },
  ]
}

Angular Service with a response Model:

export interface PostResponse {
  message: string;
  posts: Post;
}

  getPosts(): Observable<PostResponse> {
   return this.http.get<PostResponse>(this.postsUrl   '/api/posts');
  }

PostComponent inject the above Postservice:

    export interface Post {
      id: number;
      title: string;
      body: string;
    }


export class PostsComponent implements OnInit {
  posts: Post[] = [];
  constructor(private postService: PostService) {}    

    ngOnInit() {
      this.postService
       .getPosts()
       .pipe(
         map((data) => {
             console.log('data : ', data.posts._id);  // vide #1
          return {
           id: data.posts.id,                       // _id error <HERE>
           title: data.posts.title,
           content: data.posts.body,
         };
       })
      ).subscribe((response) => {
       this.posts = response;                          // error <HERE>
       console.log('posts updated : ', this.posts);
    });

}

Question.

Q-1 : On my Component when I map response data, the prop required is data.posts.id, instead of data.posts._id, but the stream data is: #1 { "_id": "618b22ff9e50776ed377c4eb", "title": "aaaaaaaaaaaaaa", "body": "xxxxxxxxxxxxx", "__v": 0 },

if I use _id, I get a error Property '_id' does not exist on type 'Post'

is this because of my interface PostResponse?

_id is comming from my mongo database, I was assuming that I had to force transforming response data to match the front-end structure where I don't use _ID but ID.

Q-2: on the subscribe, on this.posts = response I'm getting error:

Type '{ id: number; title: string; content: string; }' is missing the following properties from type 'Post[]': length, pop, push, concat, and 26 more.ts(2740)

CodePudding user response:

From what I have understand, your interfaces are wrong.

export interface PostResponse {
  message: string;
  posts: Post[];
}

export interface Post {
  _id: string;
  title: string;
  body: string;
}

Those seems to be the correct interfaces.

To get the data you should:

this.postService
       .getPosts()
       .subscribe((response) => {
         this.posts = response?.posts; 
   });

Or

this.postService
           .getPosts()
           .subscribe((response) => {
             this.posts = response?.posts?.map(res => {
               return {
                 _id: res.id,
                 title: res.title,
                 body: res.body,
               }
             }); 
       });

CodePudding user response:

You need to change id in interface POST to _id because that's what mongodb will send you. updated interface should be like this:

export interface POST{
  _id: string,
  title: string,
  body: string,  
}

And PostResponse should be:

export default PostResponse{
  message: string;
  posts: Post[];
}

Map the data in this way:

this.postService
           .getPosts()
           .subscribe((response) => {
             this.posts = response?.posts?.map(data => {
               return {
                 _id: data.id,
                 title: data.title,
                 body: data.body,
               }
             }); 
       });

CodePudding user response:

Q1 : Yes, that's because of your interface PostResponse that you use in getPosts(). Posts attribute in that interface refer to Post interface which means all attribute in posts objects is from Post Interface. Fix it with :

export interface Post {
  _id: string;
  title: string;
  body: string;

}

Q2 : You are mapping json response from PostResponse and not 'post' attribute value, so it will return object instead an array. try this:

 this.postService
   .getPosts()
   .pipe(
     map((data) => {
      return data.posts.map(v => {
       _id: v._id,                       
       title: v.title,
       content: v.body,
      })
   })
  ).subscribe((response) => {
   this.posts = response;  
});

And make post attribute type to array in PostResponse :

export interface PostResponse {
  message: string;
  posts: Post[];
 }
  • Related