superjson
superjson copied to clipboard
Annotate containers with their common types
When serialising a list of Dates, our meta will grow very large:
SuperJSON.serialize({
timestamps: [ new Date(), new Date(), new RegExp(), new Date() ]
})
// yields
{
json: ...
meta: {
values: { "timestamps.0": "Date", "timestamps.1": "Date", "timestamps.2": "RegExp", "timestamps.3": "Date" }
}
}
We could save some space by serialising to the following instead:
{
json: ...
meta: {
values: { "timestamps": ["array", "Date"], "timestamps.2": "RegExp" }
}
}
(Date is chosen because it occurs most in timestamps)
Could we use predefined numeric constants + bit comparisons to represent the types? It'll make the meta a little less human readable, but we'll save bytes in both the library and the transported JSON. We could even compile away the constants during our build which would compress the bundled code size further.
const StringType = 1;
const DateType = 2;
const ArrayType = 3;
// in untransform
switch(0) {
case fieldType ^ StringType:
return String(fieldValue);
case fieldType ^ DateType:
return Date(fieldValue);
case filedType ^ ArrayType:
return toArray(fieldValue);
// ...
}
The compiled code will look something like this (whitespace notwithstanding):
switch(0) {
case f^0: return String(v);
case f^1: return Date(v);
case f^2: return toArray(v);
// ...
And the resulting meta:
{
meta: {
values: { "timestamps.0": 2, "timestamps.1": 2, "timestamps.2": 5, "timestamps.3": 2 }
}
}
Still replicated field names, but solves the duplication of field types.
Good idea! This is one of the ideas proposed in https://github.com/blitz-js/superjson/issues/11.
Out of curiosity, what's the advantage of switch (0) { case fieldType ^ StringType: ... } over switch (fieldType) { case StringType: ... } in your code snippet?