Managing unpredictable fields within a TypeScript interface Let me known if you need further assistance

Currently, I am developing a web application using Angular and encountered an issue with the JSON data returned by a service call. The problem arises when the mapped JSON contains an Object within one of the fields with unpredictable content. How can I handle this situation in my code to access the fields within the siteContent field? Ideally, I would like to achieve something similar to the following:

return this.http.get<SiteContent>(this.apiUrl + this.endpoint + id).subscribe((obj) => {
    console.log(obj.siteContent.get("randomKey"));
})

However, attempting to retrieve a specific key using the above method results in the following error message:

ERROR TypeError: obj.siteContent.get is not a function

Below is the structure of the SiteContent interface:

export interface SiteContent {
    id: string;
    name: string;
    siteContent: Map<string,string>
}

Here is a sample JSON object for reference:

{"id":"abc123","name":"name name","siteContent":{"random1":"hi","random2":"hey"}}

For more information and to view a live example, you can visit this link: Live Example

Answer №1

JSON, derived from JavaScript object literal notation:

JSON is a format based on JavaScript object literal syntax. When utilizing the JSON.parse() method to convert a JSON string into a JavaScript value, you essentially get objects resembling JavaScript object literals:

let foo = { "a": 1, "b": "two", "c": false };
console.log(foo) // { "a": 1, "b": "two", "c": false }

let bar = JSON.parse('{ "a": 1, "b": "two", "c": false }');
console.log(bar) // { "a": 1, "b": "two", "c": false }

In JavaScript, objects consist of key-value pairs where the keys are primarily strings and the values can be of any type. These keys do not require prior declaration in JavaScript's perspective. All JavaScript objects are inherently "expando" objects.

You access an object's property either through dot notation (if the key name is a valid identifier):

foo.a;

or bracket notation (typically used when the key name isn't a valid identifier or arises from an expression result):

foo["a"];

const k = "a";
foo[k]; 

For accessing properties on such objects, avoid using get(). Instead, there exists a JS Map class which facilitates storing key-value pairs with a get() method for retrieval. Nevertheless, it's vital to note that a Map differs from a basic JS object. While there are use cases for Maps, handling deserialized JSON is typically not one of them.

Hence, your runtime code might resemble this:

let json = JSON.parse(
    '{"id":"abc123","name":"name name","siteContent":{"random1":"hi","random2":"hey"}}'
);

console.log(json.siteContent.random1); // hi

TypeScript adds a static typing system to describe JavaScript functionality without altering its behavior. An interface type like SiteContent serves as a way to define the structure of specific JavaScript objects expected at runtime.

In TypeScript, object types may possess known properties with defined string literal keys such as id or name. Moreover, employing JavaScript objects as expando objects where keys have predetermined value types but unknown beforehand is common. Hence, TypeScript enables assigning an object type with an index signature. The object type {[k: string]: number} signifies "you can index into this object with any key k of type string, and if there's a property, it shall be of type number. For instance, you desire the siteContent property to be an object type featuring arbitrary keys but containing string values:

interface SiteContent {
    id: string;
    name: string;
    siteContent: { [k: string]: string }
}

With that specified index signature, your TypeScript code will compile error-free:

let json = JSON.parse(
    '{"id":"abc123","name":"name name","siteContent":{"random1":"hi","random2":"hey"}}'
) as SiteContent;

console.log(json.siteContent.random1); // hi

Playground link to code

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

Struggling to locate root directory post-Angular 13 upgrade in Jest

After updating my project to Angular 13, I realized that Jest required some adjustments as well. Now, any mention of 'src' cannot be resolved properly. For instance: Cannot find module 'src/app/app.component/app.component.test' from & ...

Navigating Promises in Node.js: Best Practices

Seeking help with executing a callback function in nodejs using expressjs and angular 2. My process involves sending a form data to an API route, querying a MYSQL database for user details, and expecting to receive the complete user information from the ph ...

The battle of environmental impact versus utility value in the realm of constants

Imagine having a collection of links that you want to organize in a separate file like this: export const SITE_LINKS = [ { text: 'About', path: '/about' }, { text: 'Projects', path: '/projects} ] You plan to utiliz ...

Having trouble connecting 'chartData' to a 'div' in Angular 2 because it is not recognized as a valid property?

While working on my Angular project, I encountered the following error that I have been unable to resolve: EXCEPTION: Uncaught (in promise): Error: Template parse errors: Can't bind to 'chartData' since it isn't a known property of ...

Error in Directive: NgControl Provider Not Found

I encountered an issue with my Directive while attempting to inject 'NgControl' and received a 'No provider for NgControl' error. Here is the structure of my File Directory: app folder |--directives folder |--myDirec ...

Ivy workspace encountered an error with Angular being undefined: <error>

Recently, I attempted to install Angular on my MacOS terminal by entering the command $ npm install -g @angular/cli Unfortunately, the installation kept failing and the terminal displayed an error message. Subsequently, I tried the command $ sudo npm inst ...

The mapStateToProps function in a Higher Order Component is receiving an OwnProps argument with a property that is not defined

I'm a new user of react-redux trying to connect a higher-order component to the react-redux store. In the mapStateToProps function, I'm using the ownProps argument to filter the state. However, the property I'm trying to use within OwnProps ...

Can fields from one type be combined with those of another type?

Is it possible to achieve a similar outcome as shown below? type Info = { category: string } type Product = { code: string, ...Info } Resulting in the following structure for Product: type Product = { code: string, category : string } ...

Having trouble retrieving data from mongo db collection - data not found

For my eCommerce application, I am using MongoDB and Angular. The requirement is to retrieve items under each user in the cart. However, when trying to fetch the data using the object ID as a reference, it seems unable to find any data from the database. ...

Properly implement Angular/Typescript to populate an array with chosen objects

Currently, I have an Angular application that is fetching JSON resources from a Spring Boot REST API. These resources consist of simple player objects with attributes like id, name, position, and value. On the UI, each object is displayed along with a "BUY ...

Unlocking the power of URL manipulation in Fastify using Node.js

I'm attempting to retrieve specific parts of the URL from a Fastify server. For instance, the URL looks like this: http://localhost:300/query_tile/10/544/336 Within the Fastify server, I need the values for z/x/y. I've attempted the following ...

Error in Typescript: Array containing numbers is missing index property `0`

This is the code for my class: class Point{ coordinates: [number, number, number]; constructor(coordinates: [string, string, string]) { this.coordinates = coordinates.map((coordinate) => { return Math.round(parseFloat(coordinate) *100)/ ...

What is the process for switching the tile layer from OpenStreetMap to Stamen?

Exploring the possibilities of using Stamen maps with ngx-leaflet has piqued my interest. For those interested, more information on integrating leaftlet can be found here. However, the process of integrating it with ngx-leaflet remains a bit unclear to m ...

Guide on Implementing a Function Post-Rendering in Angular 2+

I'm looking to implement some changes in the Service file without modifying the Component.ts or directive file. Here's what I need: 1) I want to add an event listener after the service renders its content (which is generated by a third-party tool ...

Angular Bootstrap Datepicker provides us with a date object, but I need it in the Date format

My desired date format is "Wed Aug 07 2019 16:42:07 GMT+0530 (India Standard Time)", but instead I am receiving { year: 1789, month: 7, day: 14 } from ngbDatepicker. Any assistance on resolving this issue would be greatly appreciated. ...

When clicking initially, the default input value in an Angular 2 form does not get set

I am currently learning angular2 as a beginner programmer. My goal is to create a form where, upon clicking on an employee, an editable form will appear with the employee's current data. However, I have encountered an issue where clicking on a user f ...

Issue with drag and drop functionality in Angular 13 when using ngFor with a JSON array

Embarking on my inaugural endeavor with Angular material CDK drag and drop for one of my user stories. I'm puzzled as to why an array of objects is not functioning properly in cdk drag and drop Error message: Argument of type 'CdkDragDrop<{ ...

Restoring previous configuration in Ionic2 from the resume() lifecycle method

Encountering an issue with my ionic2 application where I save the last state in local storage when the app goes to the background. Upon resuming, it checks for the value of lastState in local storage and pushes that state if a value exists. The specific er ...

Why do the RouteConfig and classes necessitate the inclusion of a service and router in their constructors?

While working with a sample code in the Angular2 framework, specifically the Heroes sample, I have encountered something that I am struggling to understand. What determines the order of dependencies in the constructor, like Router, Service or vice versa? ...

Adjust the dimensions of an Angular Material 2 dialog by updating the width or height

Is there a way to adjust the dimensions of an open Angular Material 2 dialog, either its width or height? I attempted to modify the size of the dialog by obtaining a reference to it and using the updateSize method within the dialog. Unfortunately, I belie ...