Exploring the concept of converting a data type into an interface using map operations

Recently, I started learning Angular and I've been trying to wrap my head around how mapping from a response to an interface actually works.

Let's take a look at the API response I received:

   [ {
   "id": 2,
   "name" : "Josh",
    } ];

Here's what my TypeScript interface looks like:

   export interface User {
      name: string;
      id: number | null;
     }

In my service, I have a simple GET call:

   getUser() {
   return this.http.get<User>('http://localhost:4200/user/1').pipe(
          map((response: User) =>
          this.response = response,
          ));
      }

In the component, I subscribe to this call:

   callGetUser() {
          this.getUser().subscribe((response: User) => {
          this.user = response;
          });
   }

The 'user' object is also of type User:

   user: User;

My expectation was to have a 'user' attribute of type User. I also thought there would be an error if the response attributes did not match the User interface - such as passing an "id2" attribute.

To test this, I created an instance of User in TypeScript:

https://i.sstatic.net/qX8Ki.png

https://i.sstatic.net/E3ast.png

Now, I'm left wondering why the mapping seems to work even when attributes don't match. Shouldn't I be getting an error? Is there a way to catch the mismatch and throw an error?

Answer №1

It is important to keep in mind that Typescript gets compiled into Javascript before it is executed. Javascript does not have any type checking, so when you write

getUser() {
   return this.http.get<User>('http://localhost:4200/user/1').pipe(
   map((response: User) =>
          this.response = response,
   ));
}

you are assuming that the http request will return an Object with the same structure as User. However, during runtime, when the call is actually made, there will be no type checking because the browser reads Javascript, not Typescript. The only way to ensure the consistency of an object is to check if it has all the properties. For example, if User has an id and a name, you could modify your map as follows:

return this.http.get<User>('http://localhost:4200/user/1').pipe(
  map((response: User) =>
      if(response.id && response.name)
          this.response = response;
      else
          console.log('This is not a user!');
  ));
}

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

Animated CSS side panel

I'm currently working on creating an animation for a side menu. The animation works perfectly when I open the menu, but the problem arises when I try to animate it back closed. Is there a property that allows the animation to play in reverse when the ...

Implementing a strategy for managing multiple subdomains and angular applications in conjunction with nodejs

My goal is to implement a system with multiple dynamic subdomains for account holders, as well as an api subdomain. Here's what I envision: https://example.com --> Angular 4 public landing page app https://api.example.com --> NodeJS api https:/ ...

Tips for successfully interacting with dynamic text areas using Protractor:

My current project involves e2e testing for an Angular 4 application with Protractor. Despite my efforts, I am struggling to locate a unique id, class, name or text identifier for a specific textarea within the application code. I need assistance in find ...

Getting environment variables on the client side in Next.js: A step-by-step guide

How can I retrieve an environment variable in my Next.js application and pass the data into datadogRum.init? // _app.tsx import React from "react"; import { useEffect } from "react"; import type { AppProps } from "next/app"; ...

Issues arising from the conversion of a response obtained through an HTTP request

Here is the HTTP request that I have: storeCategory(file: File, category: CategoryModel): Observable<HttpEvent<{}>> { const formdata: FormData = new FormData(); console.log("1") formdata.append('file', file); formdata ...

The cdkDropListSortingDisabled attribute is not recognized as a valid property for the cdkDropList directive in Angular Material

I'm trying to achieve a specific use case where I need to drag and drop data from one zone (div) to another. After some research, I discovered that angular/material2 with the cdkDropList API could help me accomplish this task. Using the copyArrayitem ...

Exploring the process of associating a string with a specific enum value in TypeScript

One scenario is if you receive a string value from the server and have an enum type with string values defined. In TypeScript, how can you convert the string value to the enum type? export enum ToolType { ORA= 'orange', ST= 'stone' , ...

Tips for creating an operation within a JSON document?

Today, I am attempting to customize the appearance of my audiobook list. However, when trying to add an aspectRatio key-value pair to each object in my JSON file, I encountered an error. https://i.stack.imgur.com/Qb3TX.png https://i.stack.imgur.com/qTkmx. ...

What method is most effective for combining two JSON files in Angular?

My data includes a json file with a product list that looks like this: [{"id":76, "name":"A", "description":"abc", "price":199, "imageUrl":"image.jpg", "productCategory":[{ "categoryId":5, "category":null },{ "categoryId":6, " ...

Progressive series of observable conditions

The issue at hand: I am faced with the task of checking multiple conditions, some of which lead to the same outcome. Here is the current flow: First, I check if a form is saved locally If it is saved locally, I display text 1 to the user If not saved l ...

Invoking a Components function from a Service in Angular may lead to a potential cyclic dependency issue

I am facing a challenge where I need to call a function from my filterComponent(component) within my engagementService(service). The function in my filterComponent accesses an array that is located within the engagementService. It uses the data from this ...

Is it possible to define a namespaced external module in TypeScript?

Currently, I am dealing with some legacy js modules that are either namespaced on window or define'd if the page is using AMD. Here's an example: // foo/bar.js (function (root, factory) { if (typeof define === "function" && define.am ...

Measuring Feedback: Utilizing Angular 4 to calculate review ratings

I'm facing a challenge while working on a review form using Firebase and Angular 4. The issue is with calculating the total length of added reviews and the sum of their ratings. Each time a new review is submitted, it gets pushed to a list of objects ...

Is it more efficient to wait for the server to respond, or should I update the client immediately

Today, I found myself contemplating an interesting question. As I work on developing a Single Page Application (SPA) using Angular, I am focusing on creating a calendar module similar to Google Calendar. This module will allow users to add, edit, and remov ...

Error: Certain Prisma model mappings are not being generated

In my schema.prisma file, I have noticed that some models are not generating their @@map for use in the client. model ContentFilter { id Int @id @default(autoincrement()) blurriness Float? @default(0.3) adult ...

Preventing Firebase duplicates leads to the error of not being able to read the property 'apps'

Struggling to incorporate Firebase into a TypeScript/NextJS project, I have encountered difficulties. Despite successfully importing and initializing the app: import * as firebase from "firebase/app"; import { collection, getDocs } from "fir ...

Exclude the initial argument from functions listed within a JSON structure

Is there a way to create a generic type that reflects a JSON object structure, but excludes the first argument from functions while maintaining the types of other arguments? type InputType<T> = { increment: (state: T) => T, add: (state: T, cou ...

Taking advantage of Input decorator to access several properties in Angular 2

I am currently working on a component that is designed to receive two inputs through its selector. However, I would like to make it flexible enough to accept any number of inputs from various components. Initially, I tried using a single @Input() decorator ...

Leverage the power of Filesaver.js in conjunction with Angular

I've searched through all the articles I could find about integrating Filesaver JS with Angular, but I'm still struggling to find a solution that works for me. In my system.config.js file, I included the following code in the map section: ' ...

I am looking to access a public method from a different component in Angular 2

Trying to access the headerExpand property from app.component is causing an error message in the console: metadata_resolver.js:559 Uncaught Error: Invalid providers for "Page1" - only instances of Provider and Type are allowed, got: [?undefined?] page1 ...