Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how to parse enums without ReflectDecorators #98

Open
gthb opened this issue May 6, 2019 · 1 comment
Open

Document how to parse enums without ReflectDecorators #98

gthb opened this issue May 6, 2019 · 1 comment

Comments

@gthb
Copy link

gthb commented May 6, 2019

I want to deserialize an enum property without ReflectDecorators:

enum Color { red="RED", green="GREEN", blue="BLUE" }

@jsonObject
class Thing {
    @jsonMember({what: "todo?"})
    public color?: Color
}

console.log(TypedJSON.parse('{"color": "green"}', Thing));
// should log Object { color: "green" }

console.log(TypedJSON.parse('{"color": "infradead"}', Thing));
// should throw error

How do I populate those @jsonMember options to achieve this? Enum types don't have a constructor.

The only solution I've found is:

function deserializeColor(value: string): Color {
    const keyValue = value as keyof typeof Color;
    if (keyValue in Color) {
        return Color[keyValue];
    } else {
        throw new SyntaxError(`${keyValue} is not a valid Color`);
    }
};

@jsonObject
class Thing {
    @jsonMember({deserializer: deserializeColor})
    public color?: Color
}

but that's pretty verbose, and requires a separate deserializer function for each enum type (or at least I haven't found a workable way to make it generic).

@JohnWeisz
Copy link
Owner

JohnWeisz commented May 7, 2019

I understand it's perhaps not the most intuitive thing ever, but in the meantime, for your exact example, you have to think with the runtime code here, i.e. that your enum is in fact a string at runtime. As such, you should specify String as the member constructor (which is the same as the string primitive for TypedJSON):

enum Color { red="RED", green="GREEN", blue="BLUE" }

@jsonObject
class Thing {
    @jsonMember({ constructor: String })
    public color?: Color
}

That said though, this is not going to be value-checked at runtime. To do that, you can instead use jsonMember with an accessor, e.g.:

enum Color { red="RED", green="GREEN", blue="BLUE" }

@jsonObject
class Thing {
    private _color?: Color;

    @jsonMember({ constructor: String })
    public get color(): Color ...
    public set color(value: Color) ...
}

If you properly value-check and throw in your setter, the TypedJSON.parse call should throw on invalid values (assuming your error handler does as well, which is the default behavior). This can be simplified by using a custom decorator that value-checks assignments, as jsonMember can be used with other decorators.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants