typestack / class-transformer

Decorator-based transformation, serialization, and deserialization between objects and classes.
MIT License
6.81k stars 499 forks source link

feat: transform class including dictionary type properties #31

Open taemini opened 7 years ago

taemini commented 7 years ago

Transforming Class which have a nested Class or Class[] type properties is working well. Great Job!

But could I also transform Class with dictionary type properties?

import {Type, classToPlain} from "class-transformer";

export interface PhotoList {
    [id: string]: Photo
}

export class Album {
    id: number;
    name: string;
    @Type(() => Photo, {dictionaryType: true})  // telling it it's a dictionaryType like this...
    photos:PhotoList = {};
}

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

let plainAlbum = classToPlain(myAlbum);
let restoredAlbum = plainToClass(plainAlbum)
tucker87 commented 7 years ago

Yeah, this would be quite nice. But I don't even see where you could put a decorator to make it work. I'm pretty new to TS though.

tedwong commented 7 years ago

@pplink the dictionaryType params seems not working. Is there any settings?

NoNameProvided commented 6 years ago

Hi guys!

I have removed the +1, as they don't add to the conversation, please add a thumb up emoji to the original question if you want to show your support. Thanks!

cojack commented 5 years ago

@pplink-taemin I know what you mean, but after transpile, the interface is empty, so how do you wanna tell which property is the foreign key?

NoNameProvided commented 5 years ago

I know what you mean, but after transpile, the interface is empty, so how do you wanna tell which property is the foreign key?

The received object will have it like this:

{
  'photo': Photo, 
  'car': Car,
}

So it's doable propably, however I dont understand the clase use-case for this, as you dont want to specifiy the type for every id you recieve.

~@taemini doesn't the polymorphism covers your use case? You can take a look here: #125~ Update: after re-reading this it does not solves this use-case.

JUNNNI commented 1 year ago

For those who would need a custom Transform to handle that dictionary case:

// Custom decorator
function DictionaryTransform<T = any>(classType: new () => T): PropertyDecorator {
    // @see https://github.com/typestack/class-transformer#advanced-usage
    return Transform(({ obj, key }) => {
        const entities = {};
        const dictionary = obj[key];

        if (!dictionary) {
            return;
        }

        Object.keys(dictionary).forEach((objKey) => {
            entities[objKey] = plainToClass(classType, dictionary[objKey], {
                excludeExtraneousValues: true,
                enableImplicitConversion: true, // optional - depends on your needs
            });
        });

        return entities;
    });
}

Usage

@Exclude()
class Feature {
    @Expose()
    name: string;
}

@Exclude()
export class User {
    @DictionaryTransform(Feature)
    features: Dictionary<Feature>;
}