1

So I have a json array like this:

[
  {
    "title": "This is the first title",
    "image": "img/first_img.png"
  },
  {
    "title": "This one is the second",
    "image": "img/second_img.png"
  }
]

My goal is to map the simple json array to typescript object array, which is defined as follows.

export class GenericField {
  public Required: boolean;
  public Disabled: boolean;

  constructor() {
    this.Required = false;
    this.Disabled = false;
  }
}

export class StringField extends GenericField {
  private readonly _minLength: number | null;
  private readonly _maxLength: number | null;
  private readonly _value: string;

  constructor(
    minLength: number | null,
    maxLength: number | null,
    value: string
  ) {
    super();
    this._minLength = minLength;
    this._maxLength = maxLength;
    this._value = value;
  }
// ...
}

export class UrlField extends GenericField {
  private _url: string;

  constructor(url: string) {
    super();
    this._url = url;
  }

  public get Url(): string {
    return this._url;
  }
}

export class SliderObject {
  public title: StringField;
  public image: UrlField;

  constructor(title: string, image: string) {
    this.title = new StringField(null, null, title);
    this.image = new UrlField(image);
    this.image.Disabled = true;
  }
}

When I map with class-transformer, the objects aren't mapped correctly. How do I achieve that I can access Required field and Disabled field, which is not present in json.

Stackblitz

See my StackBlitz example here

3
  • There's no such thing as a "JSON Object" (nor a "json Object array") Commented Aug 10, 2022 at 6:59
  • Are you looking for automapper in TS like this? Commented Aug 10, 2022 at 7:02
  • "So I have a json array like this:" - No, you don't. That's an array of objects. Commented Aug 10, 2022 at 7:48

3 Answers 3

1

It would be like the following (assuming response.data is where the JSON text is).

const items: Array<{title: string, image: string}> = JSON.parse(response.data)

const sliderObjects = items.map(item =>
    new SliderObject(item['title'], item['image']))

Sign up to request clarification or add additional context in comments.

Comments

0

You can come up with your own reviver and conventions in your models to support proper deserialization.

class SliderObject {
  public title: StringField;
  public image: UrlField;

  constructor(title: string, image: string) { /* class initialization */ }

  static fromJSON(data: { image: string; title: string; }): SliderObject {
    return new SliderObject(data.title, data.image);
  }
  static isDeserializableFromJSON(data: any): data is { image: string; title: string; } {
    return data && typeof(data.image) === 'string' && typeof(data.title) === 'string';
  }
}

function jsonReviver(_: string, value: unknown): unknown {
  if (SliderObject.isDeserializableFromJSON(value)) {
    return SliderObject.fromJSON(value);
  }
  return value;
}

console.log(JSON.parse(`[/* array data */]`, jsonReviver));

In the example above I have added to static methods to SliderObject to help with serialization and a custom json reviver function. The static methods detect if data create from JSON.parse can be used to create a sliderObject and the other actually creates the new class. The reviver will call the guard method and return a SliderObject if the guard passed.

There are lots ways to skin this cat. I personally eschew TypeScript classes in favor of interfaces which I find are more flexible. Why try to make TypeScript C# or Java? By using interfaces, I can largely avoid situations like these.

Comments

0

Please check some updates that I made in order to have your object attributes accessible:

https://stackblitz.com/edit/new-project-w5b97l?file=src/app/field-definition.ts

A few notes:

  • The GET request from the slider_object.json file is NOT returning an Observable<SliderObject[]> but an Observable<SliderObjectDTO[]> (or some other name for the interface). An instance of SliderObject has the StringField attribute and the UrlField attribute, while what you are reading from the file are JSON objects (NOT SliderObject instances) which check the SliderObjectDTO interface, so they will have the title and image properties.

  • observables should follow this naming convention: observableName$, so with a $ symbol at the end, thus sliderObjects renamed to sliderObjects$

  • class attributes should not start with a capital letter, thus Required renamed to required, Disabled renamed to disabled. The same thing applies for the properties (getters)

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.