mobxjs / serializr

Serialize and deserialize complex object graphs to and from JSON and Javascript classes
MIT License
766 stars 52 forks source link

Strongly typed serialized representation #142

Closed pokey closed 3 years ago

pokey commented 3 years ago

It would be great if serialize and deserialize had strong types for the serialized data. Something like the following:

export default function serialize<T, U>(modelSchema: ClazzOrModelSchema<T, U>, instance: T): U

export default function deserialize<T, U>(
    modelschema: ClazzOrModelSchema<T, U>,
    json: U,
    callback?: (err: any, result: T) => void,
    customArgs?: any
): T

Then I'd get type checking for json. I'm guessing I'm not the first person to think of this idea, so just wanted to see why you went with any. Was it:

  1. There isn't a good use case for this functionality because usually the json comes from some weakly typed source anyway,
  2. There is some fundamental typing challenge here that makes this very difficult / impossible, or
  3. Never got around to it?

Was vaguely considering taking a swing at implementing this, but wanted to check in to see if there was good reason to leave this rock unturned. Guessing some nasty critters might crawl out, so figured I'd see if it's already been tried 😊. Thanks!

NaridaL commented 3 years ago

@pokey Unless I'm missing something, there's no type introspection on decorators, which you would need to have the type of the JSON object generated automatically. Even if there were, it looks like it would be pretty messy.

As far as I can see, in 99% of cases you're getting the JSON over the network or local storage, in which case it doesn't make any difference whether you type cast it to YourTypedJSON and then deserialize it, or just keep it as any and deserialize it.

This could make sense if you're deserializing only parts of the JSON manually, or using the JSON in other contexts, but for that I'd just suggest a wrapper:

function myDeser(modelSchema: ClazzOrModelSchema<MyObj>, json: MyTypedJSON): MyObj
function myDeser(modelSchema: ClazzOrModelSchema<MyObj2>, json: MyTypedJSON2): MyObj2
function myDeser(modelSchema: ClazzOrModelSchema<any>, json: any) {
    return deserialize(modelSchema, json)
}

or even better:

function deserializeMyObj(json: MyTypedJson): MyObj {
    return deserialize(MyObj, json)
}
// more functions ...
pokey commented 3 years ago

Yeah fair enough a wrapper is probably good enough; was imagining that the type expected for that JSON would be inferred automatically from the prop schema, but that's probably too fancy 😅. Re decorators, I'm not using them so hadn't thought about that issue; fair point