GillianPerard/typescript-json-serializer

[BUG]: Deserialize returning empty object in string property

m4kz opened this issue · 7 comments

m4kz commented

Version

5.1.0

Description

When I deserialize the class below from {"some": "something"}, i get a weird result

uid becomes an empty object, while name is undefined,.

Shouldn't uid also be undefined?

This is the resukt i get:

name: undefined
some: 'something'
uid: {}

Error

No response

Reproduction

class:

@JsonObject()
export class BaseModel {
    @JsonProperty()
    uid?: string;      
    @JsonProperty()
    some?: string|null;
    @JsonProperty() 
    name?: string | null; 
    constructor(uid?: string, some?: string | null, name?: string | null ) {
        this.uid = uid;
        this.some = some;
        this.name = name;
     }
}

Deserialize:
const deserializedbm : BaseModel= <BaseModel2>defaultSerializer.deserialize<BaseModel>({"some": "something"}, BaseModel2);

On which OS the bug appears?

Ubuntu

What is your project type?

NodeJs

On which build mode the bug appears?

No response

Anything else?

No response

Hi, thanks for using my lib.

You're right, there is weird behavior there.

Until I fix, you could declare your class as:

@JsonObject()
export class BaseModel {
    @JsonProperty()
    public uid?: string;

    @JsonProperty()
    public some?: string | null;

    @JsonProperty() 
    public name?: string | null;
}
m4kz commented

Thank you.
It works, but then i cannot have a constructor.

Yes indeed, let me fix asap.

I checked deeper and there is a problem with Typescript.

You can define a property with multiple possible types, for example: uid: string | undefined but as typescript is not actually a typed language, the type becomes Object in reality.

For a previous PR, I affected a default value equal to {} when I build an instance of the object to deserialize because of people who want to pass an object as constructor params (see: #161).

I imagine 3 solutions:

  • I keep my code unchanged and instead of having a constructor, you use the method I sent you in a comment above (because the JsonObject classes should only be used for DTO not for some logic)
  • I remove the default params from my code so your code will work but the current users that use object param will have to change their code to set a default value or use ? syntax to avoid errors
  • Change my code; instead of generating empty instances and then applying data that users pass to the deserialize function to the instance, I could try to pass the properties from data that match the constructor params and the assignment but this solution is way more tricky because I should parse the constructor as string to guess what the user had in mind
m4kz commented

Could be possible to have default configurable? either in JsonProperty? or in JsonSerializer?


const customSerializer = new JsonSerializer({
//Default type
defaultType:  ''
})

Perhaps in the JsonObject, I could create a param to provide default params for the constructor and if no one is set then i provide undefined.

The new version 6.0.0 is here.

You have nothing to do, your could should work now.
But I fou want you can specify the default values for the params of your constructor directly inside the JsonObject:

@JsonObject({ constructorParams: [undefined, null, null] })
export class BaseModel {
    @JsonProperty()
    uid?: string;      
    @JsonProperty()
    some?: string|null;
    @JsonProperty() 
    name?: string | null; 

    constructor(uid?: string, some?: string | null, name?: string | null ) {
        this.uid = uid;
        this.some = some;
        this.name = name;
     }
}