Rehydration after structural cloning
florianbepunkt opened this issue · 0 comments
Structural Cloning a BigNumber instance removes all prototype methods and leaves a plain object, e. g.
const plainObj = { s: 1, e: -2, c: [ 50 ] }
I thought that it would be possible to rehydrate/restore a BigNumber obj like const bn = new BigNumber(plainObj)
, however the resulting value is alway NaN.
TDLR
import assert from 'assert';
import BigNumber from 'bignumber.js';
const obj = { c: [50], e: 1, s: 1 };
const rehydrated = new BigNumber(obj);
assert.strictEqual(BigNumber.isBigNumber(rehydrated), true);
assert.strictEqual(rehydrated.isNaN(), false);
Why is this? I thought the object would contain all "state" that is needed to recreate a BigNumber. Is there a way to achieve what I would like to do without converting the value to a string / number first?
EDIT
The cause of this issue is that
(a) BigNumber.js accepts an object literal, but you need to provide the property _isBigNumber: true
to this literal
(b) Structured cloning removes _isBigNumber: true
from the object
import BigNumber from 'bignumber.js';
import { deserialize, serialize } from 'v8';
const obj = { c: [50], e: 1, s: 1, _isBigNumber: true };
const rehydrated = new BigNumber(obj); // working
const clone = deserialize(serialize(rehydrated)); // structure cloning node.js
const rehydratedClone = new BigNumber(clone); // not working, since clone is missing _isBigNumber: true
Could we skip the _isBigNumber: true
check in the constructor? If someone provides an object that adheres to BigNumber's data structure, couldn't we safely assume that this is a BigNumber? This would add the benefit, that BigNumber objects would be serializable via StructuredClone as well as JSON.
Possible solution
Line 191 in 690d996
Changing this to if (v && typeof v.c !== "undefined" && typeof v.s !== "undefined" && typeof v.e !== "undefined") {
would solve the issue, while all tests still pass. So, basically an obj { s: 1, e: -2, c: [ 50 ] }
is not a BigNumber, hence BigNumber.isBigNumber(obj) is false, but you can construct a BigNumber from it: new BigNumber(obj).
Then it only becomes a habit of coding to re-encode your BigNumber values before you use them, e. g.
const someFn = (valueThatMightBeSerializedOrNot: BigNumber) => new BigNumber(valueThatMightBeSerializedOrNot).plus(1);