TypeScript sorting an array

I've been trying to figure out a very strange issue I ran into with typescript. It was treating an inline Boolean expression as whatever the first value's type was instead of the complete expression.

So if you try something simple like the following:

var numericArray:Array<number> = [2,3,4,1,5,8,11]; var sorrtedArray:Array<number> = numericArray.sort((n1,n2)=> n1 > n2); 

TryIt

You will get an error on your sort method saying the parameters do not match any signature of the call target, because your result is numeric and not Boolean. I guess I'm missing something though cause I'm pretty sure n1>n2 is a Boolean statement.

0

8 Answers

Numbers

When sorting numbers, you can use the compact comparison:

var numericArray: number[] = [2, 3, 4, 1, 5, 8, 11]; var sortedArray: number[] = numericArray.sort((n1,n2) => n1 - n2); 

i.e. - rather than <.

Other Types

If you are comparing anything else, you'll need to convert the comparison into a number.

var stringArray: string[] = ['AB', 'Z', 'A', 'AC']; var sortedArray: string[] = stringArray.sort((n1,n2) => { if (n1 > n2) { return 1; } if (n1 < n2) { return -1; } return 0; }); 

Objects

For objects, you can sort based on a property, bear in mind the above information about being able to short-hand number types. The below example works irrespective of the type.

var objectArray: { age: number; }[] = [{ age: 10}, { age: 1 }, {age: 5}]; var sortedArray: { age: number; }[] = objectArray.sort((n1,n2) => { if (n1.age > n2.age) { return 1; } if (n1.age < n2.age) { return -1; } return 0; }); 
7

The error is completely correct.

As it's trying to tell you, .sort() takes a function that returns number, not boolean.

You need to return negative if the first item is smaller; positive if it it's larger, or zero if they're equal.

1

Great answer Sohnee. Would like to add that if you have an array of objects and you wish to sort by key then its almost the same, this is an example of one that can sort by both date(number) or title(string):

 if (sortBy === 'date') { return n1.date - n2.date } else { if (n1.title > n2.title) { return 1; } if (n1.title < n2.title) { return -1; } return 0; } 

Could also make the values inside as variables n1[field] vs n2[field] if its more dynamic, just keep the diff between strings and numbers.

2

Sort Mixed Array (alphabets and numbers)

function naturalCompare(a, b) { var ax = [], bx = []; a.replace(/(\d+)|(\D+)/g, function (_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) }); b.replace(/(\d+)|(\D+)/g, function (_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) }); while (ax.length && bx.length) { var an = ax.shift(); var bn = bx.shift(); var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]); if (nn) return nn; } return ax.length - bx.length; } let builds = [ { id: 1, name: 'Build 91'}, { id: 2, name: 'Build 32' }, { id: 3, name: 'Build 13' }, { id: 4, name: 'Build 24' }, { id: 5, name: 'Build 5' }, { id: 6, name: 'Build 56' } ] let sortedBuilds = builds.sort((n1, n2) => { return naturalCompare(n1.name, n2.name) }) console.log('Sorted by name property') console.log(sortedBuilds)
0
let numericArray: number[] = [2, 3, 4, 1, 5, 8, 11]; let sortFn = (n1 , n2) => number { return n1 - n2; } const sortedArray: number[] = numericArray.sort(sortFn); 

Sort by some field:

let arr:{key:number}[] = [{key : 2}, {key : 3}, {key : 4}, {key : 1}, {key : 5}, {key : 8}, {key : 11}]; let sortFn2 = (obj1 , obj2) => {key:number} { return obj1.key - obj2.key; } const sortedArray2:{key:number}[] = arr.sort(sortFn2); 
3

The easiest way seems to be subtracting the second number from the first:

var numericArray:Array<number> = [2,3,4,1,5,8,11]; var sorrtedArray:Array<number> = numericArray.sort((n1,n2) => n1 - n2); 

i use this

type SortArrayType = <T>(arr: T[]) => T[]; const sortArray: SortArrayType = (arr) => { return arr.sort((a, b) => { const strA = JSON.stringify(a); const strB = JSON.stringify(b); if (strA < strB) { return -1; } if (strA > strB) { return 1; } return 0; }); }; 

I wrote this one today while trying to recreate _.sortBy in TypeScript, and thought I would leave it for anyone in need.

// ** Credits for getKeyValue at the bottom ** export const getKeyValue = <T extends {}, U extends keyof T>(key: U) => (obj: T) => obj[key] export const sortBy = <T extends {}>(index: string, list: T[]): T[] => { return list.sort((a, b): number => { const _a = getKeyValue<keyof T, T>(index)(a) const _b = getKeyValue<keyof T, T>(index)(b) if (_a < _b) return -1 if (_a > _b) return 1 return 0 }) } 

Usage:

It expects an array of generic type T, hence the cast for <T extends {}>, as well as typing the parameter and function return type with T[]

const x = [{ label: 'anything' }, { label: 'goes'}] const sorted = sortBy('label', x) 

** getByKey fn found here

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like