Array sorting is broken with Bigint In JS?

Viewed 1837

It seems like Array.prototype.sort() is broken with BigInt

This works

const big = [1n, 2n, 3n, 4n];
big.sort();
console.log(big);
// expected output: Array [1n, 2n, 3n, 4n]

But this doesn't :(

const big = [1n, 2n, 3n, 4n];
big.sort((a,b)=>a-b);
console.log(big);
//Error: Cannot convert a BigInt value to a number

or am i doing something wrong?

3 Answers

JavaScript sort method requires a function as a parameter that can compare two elements of the array and return either a positive number, or a negative number or zero. Number is the keyword here.

BigInt operations like addition and subtraction returns BigInt type and not a Number type. And that's why the error you are getting.

So, Something like this should do the job

const big = [1n, 2n, 3n, 4n];
big.sort((a ,b) => {
  if(a > b) {
    return 1;
  } else if (a < b){
    return -1;
  } else {
    return 0;
  }
});
console.log(big);

Interestingly, MDN document that I linked to previously, also suggests how to sort an array of BigInts, and it is concise:

Copying the whole section here for posterity:

const mixed = [4n, 6, -12n, 10, 4, 0, 0n]
// ↪  [4n, 6, -12n, 10, 4, 0, 0n]

mixed.sort() // default sorting behavior
// ↪  [ -12n, 0, 0n, 10, 4n, 4, 6 ]

mixed.sort((a, b) => a - b)
// won't work since subtraction will not work with mixed types
// TypeError: can't convert BigInt to number

// sort with an appropriate numeric comparator
mixed.sort((a, b) => (a < b) ? -1 : ((a > b) ? 1 : 0))
// ↪  [ -12n, 0, 0n, 4n, 4, 6, 10 ]

The reason is that a - b in the sort callback function will return a BigInt data type, while sort expects it to return something that is (or can coerce to) a Number data type.

So you can use a > b || -(a < b) as callback expression:

const big = [10n, 9n, 8n, 7n];
big.sort((a, b) => a > b || -(a < b));
console.log(big + ""); // 7,8,9,10

Note that the first version (without sort callback) does not work in general, because then sort will compare the elements as strings. It is clear that this can yield results that are not numerically sorted:

const big = [10n, 9n, 8n, 7n];
big.sort(); // string-based sort
console.log(big + ""); // 10,7,8,9 is wrong

This might appear to be broken at first but its not, the problem is definition of the compare function is always expecting a return value of -1, 0, 1 and it has no reason to expect bigint of -1 0 1 cause they all are in range of normal int.. so this should solve

big.sort((a,b)=>a<b?-1:(a>b?1:0));
Related