TLDR: With a custom class serializer, nested fields are not serialized but copied as-is.
I have a custom class Foo that should be serialized. The class can look like this:
class Foo {
bar: any;
constructor(bar) {
this.bar = bar;
}
}
foo.bar can be anything, including a nested Map that can even contain nested instances of Foo somewhere deep.
If I define a custom transformer like this:
serializer.registerCustom(
{
isApplicable(v: unknown): v is Foo {
return v instanceof Foo;
},
serialize(foo) {
return { bar: foo.bar };
},
deserialize(data) {
return new Foo(data);
},
},
"Foo",
);
It doesn't work as expected, as the serializer 'stops' at bar and simply passes it without performing nested serialization.
I am not sure how to tell SuperJson to keep going into foo and serialize everything using all existing rules, adding all nested fields to the result meta for nested types or circular references.
Is it possible?
The expected result would be:
const json = new SuperJson();
// register my custom rule (serializer.registerCustom(...))
const nestedFoo = new Foo(0);
const someMap = new Map();
someMap.set("nested", nestedFoo);
const foo2 = new Foo(someMap);
const serialized = json.serialize(foo2);
const parsed = json.parse(serialized);
const nestedFooClone = parsed.bar.get("nested");
nestedFooClone.foo === 0; // true - they are equal
nestedFooClone === nestedFoo; // false - they are not the same instance, i.e., they are cloned
Note 2: I've tried with serializer.registerClass - the result is the same (I did check the source code of SuperJson):
const allowedProps = superJson.classRegistry.getAllowedProps(clazz.constructor);
if (!allowedProps) {
return { ...clazz };
}
const result = {};
allowedProps.forEach(prop => {
result[prop] = clazz[prop];
});
As seen above, class properties are shallowly passed over without nested serialization.
Note 3: If in the case above foo would include some circular references, the serialize result would also have them, and trying to stringify will throw an error.
Possible solution:
Possible API could look like:
serializer.registerCustom(
{
isApplicable(v: unknown): v is Foo {
return v instanceof Foo;
},
serialize(foo, serialize) {
return { bar: serialize(foo.bar) }; // <-------- Here! We perform nested serialization. It would keep serializing and adding to `meta` inside superjson result
},
deserialize(data, deserialize) {
return new Foo(deserialize(data)); // <----- Also here, before we create the instance, we de-serialize first (possibly this could be done automatically)
},
},
"Foo",
);
Or:
serializer.registerCustom would have another option isNested: boolean. If enabled, serialization output is treated as deep and traversed
Some workaround or solution would be very welcome. I am creating a generic coder/decoder that can have arbitral, possibly nested and circular data structures built using custom classes. Not being able to serialize nested properties is quite a blocker for it to work
TLDR: With a custom class serializer, nested fields are not serialized but copied as-is.
I have a custom class
Foothat should be serialized. The class can look like this:foo.barcan be anything, including a nested Map that can even contain nested instances ofFoosomewhere deep.If I define a custom transformer like this:
It doesn't work as expected, as the serializer 'stops' at
barand simply passes it without performing nested serialization.I am not sure how to tell SuperJson to keep going into
fooand serialize everything using all existing rules, adding all nested fields to the resultmetafor nested types or circular references.Is it possible?
The expected result would be:
Note 2: I've tried with serializer.registerClass - the result is the same (I did check the source code of SuperJson):
As seen above, class properties are shallowly passed over without nested serialization.
Note 3: If in the case above
foowould include some circular references, theserializeresult would also have them, and trying to stringify will throw an error.Possible solution:
Possible API could look like:
Or:
serializer.registerCustomwould have another optionisNested: boolean. If enabled, serialization output is treated as deep and traversedSome workaround or solution would be very welcome. I am creating a generic coder/decoder that can have arbitral, possibly nested and circular data structures built using custom classes. Not being able to serialize nested properties is quite a blocker for it to work