Developing interfaces for complex data structures in Angular and TypeScript使 can greatly improve code readability and

Lately, I've been investing a significant amount of time attempting to apply interfaces to the JSON response received from the API. Surprisingly, it works perfectly fine in the browser after compilation, but my IDE, VS Code, keeps throwing this error at me: "Identifier 'title' is not defined. 'RoomItem[]' does not contain such a member." It's frustrating because despite displaying the elements correctly, VS Code insists on underlining the data properties in red. To add to my woes, my terminal also throws a warning my way.

WARNING in AngularCompilerPlugin: Forked Type Checker exited unexpectedly. Falling back to type checking on main thread.

If anyone out there could lend a hand, I would deeply appreciate it - have a wonderful day, fellow developers!

// JSON Response

area: "21 - 28 m²"
day_price_flex: "1647.00"
day_price_normal: "1318.00"
description: "Our beautiful superior rooms offer more space for relaxation after a long day on holiday. Watch a movie on the TV or enjoy some downtime in the bathtub."
facilities: (12) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
id: "2"
images: [{…}]
num_facilities: 12
num_images: 1
num_persons: "2"
title: "Superior"

// Facilities

facilities: Array(12)
0: {id: "1", title: "Electric kettle with coffee/tea", category: "General equipment"}
1: {id: "2", title: "Free WiFi", category: "General equipment"}
2: {id: "3", title: "Hairdryer", category: "General equipment"}
3: {id: "4", title: "Non-smoking", category: "General equipment"}
4: {id: "5", title: "Air cooling", category: "General equipment"}
5: {id: "6", title: "Minibar", category: "General equipment"}
6: {id: "7", title: "Blackout curtains", category: "General equipment"}
7: {id: "8", title: "Safe", category: "General equipment"}
8: {id: "9", title: "Iron and ironing board", category: "General equipment"}
9: {id: "10", title: "French balcony (available in some rooms)", category: "General equipment"}
10: {id: "25", title: "Two separate single beds", category: "Beds"}
11: {id: "26", title: "King-size bed", category: "Beds"}

// Images

0: {id: "75", title: "Superior Sleeping Space ©", image: "/images/room-superior-bedroom.jpg"}


// HTML / View

<section *ngIf="http.data | async as data">
    <article>
        <h2>{{data.title}}</h2>
        <h5>{{data.area}}</h5>
        <p>{{data.description}}</p>
    </article>
</section>
// http.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { map, catchError, shareReplay } from 'rxjs/operators';

interface Facilities {
  id?: string;
  title?: string;
  category?: string;
}

interface Images {
  id?: string;
  title?: string;
  image?: string;
}

interface RoomItem {
  id: string;
  title: string;
  description: string;
  num_persons: string;
  area: string;
  day_price_normal: string;
  day_price_flex: string;
  num_images: number;
  images?: Images[];
  num_facilities: number;
  facilities?: Facilities[];
}

interface Response {
  status: boolean;
  error: string;
  item?: RoomItem[];
  items?: RoomItem[];
}


const CACHE_SIZE = 1;

@Injectable({
  providedIn: 'root'
})
export class HttpService {
  private cache$: Observable<RoomItem[]>;

  constructor(private http: HttpClient) {}
  
   get data() {
    if (!this.cache$) {
      this.cache$ = this.requestRoom(2).pipe(shareReplay(CACHE_SIZE));
    }
    
    return this.cache$;
   }

   private requestRoom(id) {
     return this.http.get<Response>(`https://api.mediehuset.net/overlook/rooms/${id}`).pipe(
       map(response => response.item ? response.item : response.items)
     );
   }

}

Despite my attempts to remove the array part of my type, I faced compilation issues because I use a map operator on it - which wouldn't be feasible without an array. Changing my cache observable to exclude the array ("Observable<RoomItem>") didn't work either - leading me to adjust the Response interface accordingly, but still no success.

// If i change my cache observable to not having it:

Observable<RoomItem>

// I had to change it in my Response type as well..

interface Response {
  status: boolean;
  error: string;
  item?: RoomItem;
  items?: RoomItem;
}

// I actually also tried with RoomItem<Object>, with compilation success but no results on the functioning part of it.

This entire ordeal left me questioning what to do next. While my code may trigger red underlines in my IDE, it still compiles successfully and functions properly by displaying the items. Perhaps creating individual files for the interfaces to import them into their respective locations would streamline the process moving forward.

Answer №1

When working with services, you may need to handle different responses based on certain conditions, such as returning a single item { } or multiple items [ ]. In these cases, you can cast the return type to accommodate both scenarios, like

Observable< RoomItem | RoomItem[]>

Service Operation

get data(): Observable< RoomItem | RoomItem[]> {
        if (!this.cache$) {
            this.cache$ = this.requestRoom(2).pipe(shareReplay(CACHE_SIZE));
        }

        return this.cache$;
    }

    private requestRoom(id) {
        return this.http
            .get<Response>(`https://api.mediehuset.net/overlook/rooms/${id}`)
            .pipe(map((response) => (response.item ? response.item : response.items)));
    }

HTML Component

<section *ngIf="http.data | async as data">
    <article *ngIf="!isDataAnArray(data); else displayArrayData">
        <h2>{{data.title}}</h2>
        <h5>{{data.area}}</h5>
        <p>{{data.description}}</p>
    </article>
    <ng-template #displayArrayData>
      <article>
       <div *ngFor="let item of data">
            <h2>{{item.title}}</h2>
            <h5>{{item.area}}</h5>
            <p>{{item.description}}</p>
        </div> 
    </article>
    </ng-template>
</section>

Component Method

isDataAnArray(data: RoomItem | RoomItem[]){
        retun Array.isArray(data);
    }

Interface Definition

interface Response {
  status: boolean;
  error: string;
  item?: RoomItem;
  items?: RoomItem[];
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Refresh Angular to Ensure Accurate Printing

My Angular page is designed for user printing, featuring a large "Print" button. Upon clicking this button, I wish to hide it, print the page, and then display the button again. The initial state of the ToggleForPrint variable is false. <ng-container * ...

Make sure to send individual requests in Angular instead of sending them all at once

I am looking to adjust this function so that it sends these two file ids in separate requests: return this.upload(myForm).pipe( take(1), switchMap(res => { body.user.profilePic = res.data.profilePic; body.user.coverPic = res.data.coverPic; ...

Is there a way to trigger the opening of the mat-autocomplete panel when an option is selected in a different mat-autocomplete component?

Is it possible to trigger the opening of a mat-autocomplete panel when an option is selected in another mat-autocomplete? To see an example, please check out this demo. ...

Make sure PTable maintains a horizontal layout on any device with PrimeNG

When I view my Ptable on desktop or iPad, it looks like this: https://i.stack.imgur.com/ONqZV.png However, when I switch to a device like an iPhone X, it changes to this layout: https://i.stack.imgur.com/H2q7j.png I want the horizontal layout to displa ...

Using Javascript to parse SOAP responses

Currently, I am working on a Meteor application that requires data consumption from both REST and SOAP APIs. The SOAP service is accessed using the soap package, which functions properly. However, I am facing challenges with the format of the returned data ...

Is it better for a component's render function to have a return type of React.ReactNode or JSX.Element?

While both options do not produce compilation errors, is there a difference between the two and is one more preferable than the other? ...

TypeScript encountered an unexpected { token, causing a SyntaxError

Despite multiple attempts, I can't seem to successfully run my program using the command "node main.js" as it keeps showing the error message "SyntaxError: Unexpected token {" D:\Visual Studio Code Projects\ts-hello>node main.js D:&bsol ...

The displayed session in the Ionic App component.html is not appearing

When attempting to display a session in HTML named {{nama_cust}} on app.component.html, I encountered an issue where nothing appeared or it showed up blank. Is there an error in the code? Or is it possible that the app.component cannot process sessions? He ...

Updating data in parent state with angular 2 ui-router

I am working on a project that utilizes Angular 2 and UI-ROUTER (not NgRoute). The project includes: a parent state 'parent', which controls the view of Header and Control as depicted in the image below, two child states 'childA ...

Access to Angular CORS request has been blocked

I'm currently working on establishing a connection between my Angular application and a basic REST server using express. The server responds to requests with JSON data exclusively. To enable CORS support, I've integrated the cors module from npm ...

The result should display the top 5 application names based on the count property found within the ImageDetails object

data = { "ImageDetails": [ { "application": "unknownApp, "count": 107757, }, { "application": "app6", "count": 1900, }, { & ...

Issue encountered: Jest-dom is throwing a TypeError because $toString is not recognized as a function on a project using Typescript, React

I have been facing a challenge while setting up jest and @testing-library/jest-dom for my typescript/react/next.js website. Each time I try running the tests, an error occurs, and I am struggling to identify the root cause. This issue has been perplexing ...

"Encountering issues with Firebase deployment related to function-builder and handle-builder while working with TypeScript

I encountered 4 errors while executing firebase deploy with firebase cloud functions. The errors are originating from files that I didn't modify. node_modules/firebase-functions/lib/function-builder.d.ts:64:136 - error TS2707: Generic type 'Req ...

Guide to accessing the request object within the entity class in NestJS

Currently tackling a project in nestJs that requires adding audit columns to certain entities. I have set up user information on a request object, which seems to be working fine when printed in the controller. However, I am facing issues with implementing ...

Next.js is failing to infer types from getServerSideProps to NextPage

It seems like the data type specified in getServerSideProps is not being correctly passed to the page. Here is the defined model: export type TypeUser = { _id?: Types.ObjectId; name: string; email: string; image: string; emailVerified: null; p ...

Using Pipes to Truncate Text in Angular 4 with PrimeNg

Is there a way to limit the output of a data-table to 150 characters? Here is the pipe I am using: transform(value: string, args: string[]): string { const limit = args.length > 0 ? parseInt(args[0], 10) : 20; const trail = args.length > 1 ...

Typescript throwing an error stating "Error parsing: Enum member names must not begin with lowercase letters 'a' through 'z'"

Within my typescript project, I am utilizing the following enum type: export enum ModelAttributeTypes { binary = 'binary', binarySet = 'binarySet', bool = 'bool', list = 'list', map = 'map', num ...

The Angular 2 project, built with the CLI tool, has been transformed into an npm

We have a project in the works that involves creating a large application using angular 2. This project consists of one main parent angular 2 application and three separate sub-child applications that are unrelated to each other. Each of these sub-child ...

Tips for utilizing a particular field in a JSON object as the data origin while employing ng2-completer

As a newcomer to Angular and ng2 completer, I am working with an array of objects structured like this: var concepts = [ { id:, code:, concept:, display: } ............ ] The goal is to have the data source for auto suggest feature as the di ...

Preventing Mouse Click Events Outside a Defined DIV in Angular Depending on a Condition

I am currently utilizing a RAD tool that automatically generates Angular code, and I am interested in altering specific behavior. Within the app, there is a grid, and when a user clicks an "Edit" button, it goes into edit mode for a particular row. Howeve ...