class-transformer icon indicating copy to clipboard operation
class-transformer copied to clipboard

feature: Top level abstract class parsing

Open kwek20 opened this issue 2 years ago • 1 comments

Description

I have an abstract type with child classes which i receive from the server. I would like to transform that directly into its proper class without having to write my own parse method

This works when the main class has a variable that is annotated using @Type obviously, however this doesnt help me when the object is just a Photo.

Example json:

{
    type: "Landscape",
    id: 634,
    filename: "myphoto.jpeg"
}
import { Type, plainToClass } from 'class-transformer';

export abstract class Photo {
  id: number;
  filename: string;
}

export class Landscape extends Photo {
  panorama: boolean;
}

export class Portrait extends Photo {
  person: Person;
}

export class UnderWater extends Photo {
  depth: number;
}

let photo = plainToClass(Photo, photoJson);
// now photo needs to be whichever subtype 

Currently i have to write something like this:

public static parse(data: any): Photo{
        if (data.type == PhotoType.Landscape ) {
            return plainToInstance(Landscape, data) as any;
        } else if (data.type == PhotoType.Portrait ) {
            return plainToInstance(Portrait , data) as any;
        }
}
        

Proposed solution

A class annotation for decorors, possibly similar to this repo: https://github.com/edcarroll/ta-json#usage-4

kwek20 avatar Jun 06 '23 11:06 kwek20

To add to this, is also really similar pattern to resolving Unions in type-graphql (and graphql in more constructive manners). Would think this could be done via like so:

Type-graphql already does this

https://typegraphql.com/docs/unions.html#resolving-type

knovu avatar Jun 06 '23 20:06 knovu

Hello @kwek20,

I assume you would like to extend the current discriminator solution to work on the base abstract class level as well? Is that right? So you would like to do something like:

@Type({
  discriminator: {
    property: '__type',
    subTypes: [
      { value: Landscape, name: 'landscape' },
      { value: Portrait, name: 'portrait' },
      { value: UnderWater, name: 'underwater' },
    ],
  },
})
export abstract class Photo {
  id: number;
  filename: string;
}

export class Landscape extends Photo {
  panorama: boolean;
}

export class Portrait extends Photo {
  person: Person;
}

export class UnderWater extends Photo {
  depth: number;
}
let album = plainToInstance(Photo, photoJson);

diffy0712 avatar May 08 '24 21:05 diffy0712

@diffy0712 yes that is correct! This would also mean not having to copy/ref the discriminator on each class that has the type. Im a bit suprised about the reply though, i thought this project was on hold. Good to see life again!

kwek20 avatar May 14 '24 10:05 kwek20

Thank you for the reply,

I still have to check if there were any discussion on this topic already, but I think this could be useful.

I myself would have already needed this feature too :)

We try to get some work done on class-transformer, hopefully we will have time to do so :)

diffy0712 avatar May 14 '24 15:05 diffy0712

@kwek20 there is already a really old discussion and pr on this topic. I will try to read through the issue and the pr and maybe we can do something with it.

Duplicate of https://github.com/typestack/class-transformer/issues/223

diffy0712 avatar May 15 '24 19:05 diffy0712