serialazy icon indicating copy to clipboard operation
serialazy copied to clipboard

Custom serialization for enum type

Open zett42 opened this issue 4 years ago • 0 comments

I wanted to do something like this to define custom enum serialization (e. g. to serialize enum value as string instead of number):

@Serialize.Type({ ... })
enum MyEnum { a, b, c }

Unfortunately this doesn't work, because TS compiler says "Decorators are not valid here".

As a workaround we can wrap the enum inside a class. Then we can add decorator to the wrapper class. Maybe this is something you want to add to your library?

Here is the code of my TS module (2 files including Jest unit tests): https://gist.github.com/zett42/bbd427e66cfabe3045ed73761d386a91

Usage example for serialization:

enum BallSizeEnum {
    little,
    normal,
    big, 
}

@SerializeEnumWrapper( BallSizeEnum )
// By default, enum is serialized as the string key. To serialize as the value:
//@SerializeEnumWrapper( BallSizeEnum, { serializeAsKey: false } )
class BallSize {
    constructor( public value: BallSizeEnum = BallSizeEnum.normal ) {}
}

class Ball {
    @Serialize() size: BallSize = new BallSize( BallSizeEnum.big );
}

Usage example for reflection: (requires TS compiler option emitDecoratorMetadata)

enum BallSizeEnum {
    little,
    normal,
    big, 
}

@SerializeEnumWrapper( BallSizeEnum, {
    // Add optional meta data per enum key. Values can be anything. 
    valuesDescriptor: {
        little: "Little Ball",
        normal: "Normal Ball",
        big: { more: "info" },
    } 
})
class BallSize {
    constructor( public value: BallSizeEnum = BallSizeEnum.normal ) {}
}

const ballSize = new BallSize;

console.log( getEnumValuesMetadata( ballSize ) );
// ... prints {0: "little", 1: "normal", 2: "big", little: 0, normal: 1, big: 2}

console.log( getEnumValuesDescriptorMetadata( ballSize ) );
// ... prints {little: "Little Ball", normal: "Normal Ball", big: {…}}

Revisions of this post: Jan-05-2020

  • Moved code to Gist
  • Support string enums
  • Override standard methods valueOf(), toString() and toJSON() of the prototype of the wrapper class to "unwrap" the native enum value. Add option 'toJsonAsKey' so that toJSON() writes the key instead of the value (default).
  • Add unit tests (Jest).

Jan-03-2020

  • Made the decorator function typesafe:
    • A compile error gets raised if the 'value' property of the wrapper class is of a different enum type than what is passed to the decorator function.
    • When the valuesDescriptor option is specified, ist must have a property for each enum key. Otherwise a compile error gets raised.

zett42 avatar Jan 01 '20 19:01 zett42