Converting JSON data to TypeScript objects with a focus on inheritance

I currently have three classes:

class Device{
    name:string;
}

class Mobile extends Device{
    number:string;
}

class Computer extends Device{
    macAddress:string;
}

In addition to these classes, I also have some data in JSON format:

[{
'name':'mobile1',
'number':'600 600 600',
'class':'Mobile'
},{
'name':'computer',
'macAddress:'123123123',
'class':'Computer'
}]

I am wondering if there is a way to use decorators or any other methods to generate a list of devices with their correct object types. I am producing JSON on my website and may need to add more fields or adjust the structure to ensure that TypeScript objects are generated correctly.

I have searched for solutions to this problem but have not found anything successful yet.

Best regards, Adrian

Answer №1

In my recommended approach, I propose the following implementation with explanatory comments. It is important to note that there may be errors in the code as it has not been verified, therefore additional refinement may be required.

Main Concept: Simplify the code within your components by encapsulating your array into an object named JsonDevices. Subsequently, you can create a custom converter to handle the conversion process seamlessly.

Key Classes

// Custom serialization/deserialization logic.
// Implementation of serialize and deserialize methods is mandatory.
@JsonConverter
class DeviceConverter implements JsonCustomConvert<Device> {

    // Serialization of the instance using json2typescript standard method.
    serialize(device: Device): any {
        const jsonConvert: JsonConvert = new JsonConvert();
        return jsonConvert.serialize(device);
    }

    // Upon receiving a JSON object (not string), determine whether to instantiate Computer or Mobile based on provided properties.
    deserialize(device: any): Device {

        const jsonConvert: JsonConvert = new JsonConvert();

        // Try/catch block used due to potential errors in deserialization
        try {
            if (device.name && device.macAddress) {
                const computer: Computer = new Computer();
                computer.name = device.name;
                computer.macAddres = device.macAddress;
                return jsonConvert.deserialize(computer, Computer);
            } else if (device.name && device.number) { 
                const mobile: Mobile = new Mobile();
                mobile.name = device.name;
                mobile.number = device.number;
                return jsonConvert.deserialize(mobile, Mobile);
            }
        } catch(e) {}

        throw new TypeError();

    }

} 

@JsonObject
class JsonDevices {
    @JsonProperty("devices", DeviceConverter)
    devices: Device[] = [];
}

@JsonObject
class Device {
    @JsonProperty("name", String)
    name: string = undefined;
}

@JsonObject
class Mobile extends Device {
    @JsonProperty("number", String)
    number: string = undefined;
}

@JsonObject
class Computer extends Device {
    @JsonProperty("macAddress", String)
    macAddress: string = undefined;
}

Utilization

// Sample incoming JSON data
const jsonString: string = ("
    [{
        'name':'mobile1',
        'number':'600 600 600',
        'class':'Mobile'
    },{
        'name':'computer',
        'macAddress:'123123123',
        'class':'Computer'
    }]
");

// Convert JSON string to JavaScript object
const jsonArray: any[] = JSON.parse(jsonString);

// Group the array under an object containing a device array
const jsonDevicesObject: any = {
    devices: jsonArray;
}

// Perform deserialization using json2typescript:
const jsonConvert: JsonConvert = new JsonConvert();
const jsonDevices: JsonDevices = jsonConvert.deserialize(jsonDevicesObject, JsonDevices);

// Each element within jsonDevices.devices will now represent either a Mobile or Computer instance

Answer №2

My solution is heavily influenced by the insights shared by andreas, for which I am grateful. To implement a successful resolution, I utilized an exceptional library called json2typescript . Here is how my solution looks:

import {JsonObject, JsonProperty, JsonConverter, JsonCustomConvert, JsonConvert} from "json2typescript";

@JsonConverter
class DeviceConverter implements JsonCustomConvert<DeviceDto[]> {

  // Serializing the instance using standard json2typescript method.
  serialize(device: DeviceDto[]): any {
    const jsonConvert: JsonConvert = new JsonConvert();
    return jsonConvert.serialize(device);
  }

  // Deserializing json object to choose between instances of Computer or Mobile.
  deserialize(devicesInput: any): DeviceDto[] {

    const jsonConvert: JsonConvert = new JsonConvert();

    let devices: Array<DeviceDto> = new Array<DeviceDto>();
    for (let device of devicesInput) {
      if (device['type'] == 'mobile') {
        let temp:MobileDeviceDto=jsonConvert.deserialize(device, MobileDeviceDto)
        devices.push(temp);
      } else if (device['type'] == 'rpi') {
        devices.push(jsonConvert.deserialize(device, RaspberryPiDeviceDto));
      }
    }
    return devices;
  }

}

@JsonObject
export class DevicesDto {
  @JsonProperty("devices", DeviceConverter)
  devices: DeviceDto[] = [];
}

@JsonObject
export class DeviceDto {
  @JsonProperty("name", String)
  name: string= undefined;
  @JsonProperty("description", String)
  description: string= undefined;
  @JsonProperty("type", String)
  type: string= undefined;

}

@JsonObject
export class MobileDeviceDto extends DeviceDto {
  @JsonProperty("number", String)
  number: string = undefined;
}

@JsonObject
export class RaspberryPiDeviceDto extends DeviceDto {
  @JsonProperty("version", String)
  version: string = undefined;
}

How to use this:

 let jsonConvert: JsonConvert = new JsonConvert();
 let devices: DeviceDto[] = jsonConvert.deserialize(data, DevicesDto).devices;
 this.subjectDeviceList.next(data);

I appreciate your help and guidance :)

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

How can I access a value from ngx-cookie-service prior to the application loading?

When a user reloads the page, I am facing an issue. Upon app startup, there is a short delay (100-400ms) required to fetch a value from the cookie. During this brief period, the user is temporarily redirected to the login page, but once the cookie value is ...

A Guide to Handling Errors while Converting a Map to a Promise in Typescript

I am attempting to capture errors if any of the asynchronous code within my map function fails. It seems to enter the error block but does not log anything, as the error variable remains null. Is there an alternative method for handling errors within map ...

The comparison between 'MutableRefObject<string | null>' and 'string' will never be true, as they do not share any common types. Error code: TS2367

Struggling with a React and TypeScript issue I have stored the email and password in state variables const emailRef = useRef<string | null>(null); const passwordRef = useRef<string | null>(null); This is how I set them: const onEmailChange = ...

The NestJS library has not been included in the imports

After using the nest js cli to create a library, I initially built it. But when attempting to import it as a module, there was an issue with recognition. The error message displayed: "Cannot find module '@app/big-query' or its corresponding type ...

What could be the reason for encountering an "Uncaught Runtime Error" specifically on an Android emulator while using a React app?

I'm encountering an issue when trying to launch a web-based React app on Chrome within an Android emulator. The error message I'm receiving is as follows: "Unhandled Runtime Error Uncaught SyntaxError: Unexpected Token ." Interestingly, the same ...

"Why Injecting HttpClient in Angular 4 can be a Game-Changer? Let's

According to the documentation provided by Angular, the HttpClient is injected into the main app component. However, I came across another guide that simply referred to this as a "favorable" practice without providing any explanation. @Component(...) expo ...

Creating an index signature in TypeScript without having to use union types for the values - a comprehensive guide

Is it possible to define an index signature with strict type constraints in TypeScript? interface Foo { [index: string]: number | string } However, I require the value type to be either number or string specifically, not a union of both types (number | ...

Exploring Apache NiFi version 9.0.0-m4: Attempting to assign a flow attribute based on JSON data

I am attempting to extract the monitoringType from the content and then assign it to the flow attributes for later use in routing to a specific elastic index [ { ... "Average_Wait_on_Journal" : 0.007984, "monitoringType" : &quo ...

"Although the Set-cookie is present in the response header, it is not being properly

I developed a GraphQL server using apollo-server-express, and it is currently running on localhost:4000. Upon sending a query from GraphQL playground, the response includes a set-cookie in the header: response header However, when checking the storage &g ...

Struggling with generating a collection of JSON objects to be utilized in a Kendo grid

Currently, I am facing the task of transforming a server response that is in array format into an array of JSON objects for proper functionality with the Kendo UI grid widget. To ensure the Kendo UI grid works seamlessly, the rows of data received from th ...

Initiate npm start with CORS enabled

Currently, I am developing a small application using Angular2. Following the instructions provided in the 5min. Quickstart Guide, I used npm to install necessary modules and initiate a lite-server. However, my ultimate goal is to integrate this app into ...

Tips for customizing the default name of the 'Page View' feature

After incorporating Angulartics2GoogleTagManager into the app.component, is it feasible to modify the default name of the tracked page view event from "Page View"? I require a different name than the current one. ...

Iterating Through an Array using Foreach Loop in PHP after using json_decode

I am having some issues with a foreach loop that I'm trying to run through an array. Specifically, I keep coming across the error message "Undefined index: text". Here is the code snippet in question: $tweets = json_decode($response,true); foreach ( ...

After migrating my project from Angular 2 to Angular 5, the typings are completely chaotic

Recently, I encountered issues while compiling my project after updating to angular 5. The compilation process seems to be failing due to some errors in typing. Initially, the project utilized typings, but I attempted to switch to the modern approach by us ...

Looping through NavItems component using JavaScript or Angular

My Angular project includes a navbar component with an app sidebar that has a navItems attribute. Below is the content of my navBar: <app-header style="background-color : #e65100;" [fixed]="true" [navbarBrandFull]="{ src: &a ...

Error with Angular XSRF validation following a Jira post request

Encountering an issue with a post request while attempting to add a new member to JIRA. The process works smoothly on Firefox and Internet Explorer, but consistently fails on chrome due to XSRF check failure. Unable to find a resolution for this problem. S ...

"Attach JSON data to populate the list of available tags in the tag-it

Visit I experimented with configuring it as follows: availableTags: [{ label: "JAVA(10)", value: 10 }, {label: "JAVA SCRIPT(11)", value: 11 } ], My goal is to retrieve all language IDs from the autocomplete ...

Transfer data as JSON from Flask to JavaScript

Having trouble sending data from Flask to JavaScript. I have the information from the database and added it to a dictionary. Now, I want to convert this data into a JSON object in JavaScript to display it on a map. Despite using JSON.parse in JavaScript, i ...

ion-infinite-scroll activating at rare intervals

Trying to implement ionInfiniteScroll functionality, but encountering issues. The code works in other areas of the app and on a similar page. However, when scrolling down, nothing happens - no loading animation appears. The console message within the doInf ...

Is there a way to convert HTML websites into JSON format using Cheerio and Puppeter?

Just dipping my toes into the world of JS here. I have a burning question - How exactly can we scrape an HTML website and store it as a JSON file? https://i.sstatic.net/BJtwO.png The website in question is an examination test portal. It's loaded wit ...