flightcontrolhq / superjson

Safely serialize JavaScript expressions to a superset of JSON, which includes Dates, BigInts, and more.
https://www.flightcontrol.dev?ref=superjson
MIT License
4.01k stars 87 forks source link

`NaN` values in `Float64Array` are incorrectly serialised as `null` #292

Open triglav opened 1 month ago

triglav commented 1 month ago

Float64Array accepts only numbers, null is not a valid value for this type. Unfortunatelly NaN values within the array are serialised as null, which then naturally comes back after deserialising as 0. This essentially results in data loss/corruption.

Simple example to reproduce/observe the problem:

const a0 = new Float64Array([NaN, 0, NaN, 1]);
const a1 = stringify(a0);
console.log("a1", a1); // [null,0,null,1]
const a2 = parse<Float64Array>(a1);
console.log("a2", a2); // [0, 0, 0, 1]

const b0 = NaN;
const b1 = stringify(b0);
console.log("b1", b1); // "NaN"
const b2 = parse<number>(b1);
console.log("b2", b2); // NaN
triglav commented 1 month ago

A quick naive way to fix the problem:

SuperJSON.registerCustom<Float64Array, string>(
    {
        isApplicable: (v): v is Float64Array =>
            Object.prototype.isPrototypeOf.call(Float64Array.prototype, v),
        serialize: v => v.join(","),
        deserialize: v => new Float64Array(v.split(",").map(e => +e)),
    },
    "Float64ArrayCustom"
);