0

I have three classes

class Device{
    name:string;
}

class Mobile extends Device{
    number:string;
}

class Computer extends Device{
    macAddress:string;
}

and json

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

is it possible using some kind of decorators/or anything else to get List of devices with correct object types. I'm producting Json at my site so i can also add another fields, change structure to make typescript object list generate corectly

I was searching for any solution without success.

Regards, Adrian

2
  • 1
    Hi Adrian, I think your third class should be named 'Computer'. Other than that, you could try parsing the JSON object to a let: Mobile or Computer, and see if it works. Commented Oct 6, 2017 at 8:26
  • Thanks, now its correct Commented Oct 6, 2017 at 8:36

2 Answers 2

1

I would suggest the following implementation. Please note the comments inside. It might contain some errors because I cannot actually check the code, so maybe some more work is necessary.

Basic idea: To make code simple in your components, you should wrap your array into an object, here called JsonDevices. Then you can write a custom converter and let the magic happen inside the converter.

Classes

// Custom serializer/deserializer.
// You must implement serialize and deserialize methods
@JsonConverter
class DeviceConverter implements JsonCustomConvert<Device> {

    // We receive the instance and just serialize it with the standard json2typescript method.
    serialize(device: Device): any {
        const jsonConvert: JsonConvert = new JsonConvert();
        return jsonConvert.serialize(device);
    }

    // We receive a json object (not string) and decide 
    // based on the given properties whether we want to 
    // create an instance of Computer or Mobile.
    deserialize(device: any): Device {

        const jsonConvert: JsonConvert = new JsonConvert();

        // We need the try/catch because of deserialize inside
        try {
        if (device.name && device.macAddress) {
                const computer: Computer = new Computer();
                computer.name = device.name;
                computer.macAddress = 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;
}

Usage

// Assume this is your incoming json
const jsonString: string = ("
    [{
        'name':'mobile1',
        'number':'600 600 600',
        'class':'Mobile'
    },{
        'name':'computer',
        'macAddress:'123123123',
        'class':'Computer'
    }]
");

// Convert it to an JSON/JavaScript object
// In the current Angular 4 HttpClientModule API, 
// you would get an object directly and you wouldn't 
// bother with it anyway.
const jsonArray: any[] = JSON.parse(jsonString);

// Make sure the given array is added to an object 
// having a device array
const jsonDevicesObject: any = {
    devices: jsonArray;
}

// Now deserialize the whole thing with json2typescript:
const jsonConvert: JsonConvert = new JsonConvert();
const jsonDevices: JsonDevices = jsonConvert.deserialize(jsonDevicesObject, JsonDevices);

// Now all elements of jsonDevices.devices are of instance Mobile or Computer
Sign up to request clarification or add additional context in comments.

1 Comment

It might be smarter (or even necessary?) to use Mobile|Computer instead of Device as type hints.
1

I've based my solution on what andreas wrote thank You. To achieve proper solution i've used aswesome library json2typescript . My Solution:

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


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

  // We receive the instance and just serialize it with the standard json2typescript method.
  serialize(device: DeviceDto[]): any {
    const jsonConvert: JsonConvert = new JsonConvert();
    return jsonConvert.serialize(device);
  }

  // We receive a json object (not string) and decide
  // based on the given properties whether we want to
  // create an instance 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;
}

Usage:

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

Thank You very much :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.