Large Integers in JavaScript
Recommended Approach
Example Code
const res = await axios('https://example.com/rpde/scheduled-sessions', {
// Ensure that fidelity is not lost in the JSON parsing process.
transformResponse: (res) => jsonParseConvertingTooLargeInt(res),
});
// Store `modified`s as strings
const rpdeItemsWithStringModifieds = res.data.items.map((item) => ({
...item,
modified: String(item.modified),
});
for (const rpdeItem of rpdeItemsWithStringModifieds) {
const existingItem = rpdeItemCache[rpdeItem.id];
// Temporarily use the BigInt type for numeric comparison
if (existingItem && BigInt(rpdeItem.modified) < BigInt(existingItem.modified)) {
continue;
}
rpdeItemCache[rpdeItem.id] = rpdeItem;
}
// --- A DIFFERENT MODULE - JSON PARSING UTILS ---
const { parse, isInteger } = require('lossless-json');
/**
* @param {string} s
*/
function jsonParseConvertingTooLargeIntsToBigInts(s) {
return parse(s, null, convertNumberToBigIntIfTooLargeInt);
}
/**
* This is called for ALL numeric fields in the response — not just `.modified`.
* So, we only use custom de-serialization if the value is out of normal integer
* bounds.
* There is a possibility that fields other than `.modified` will be caught by
* this function as there are other integer fields in Opportunity data. This is
* we transform, just for the de-serialization process, these values to BigInt
* rather than string, which will make it easier to deal with cases in which
* another numeric field (e.g. remainingUses) is surprisingly a very large
* integer.
*
* @param {string} value
* @returns {number | bigint}
*/
function convertNumberToBigIntIfTooLargeInt(value) {
if (isInteger(value)) {
const asInt = parseInt(value, 10);
/* Note we consider equality to either of the bounds to be "too large" just
to be extra cautious against the effects of precision loss */
if (asInt >= Number.MAX_SAFE_INTEGER || asInt <= Number.MIN_SAFE_INTEGER) {
return BigInt(value);
}
return asInt;
}
return parseFloat(value);
}Last updated