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); 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.
08 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; }); 7The 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.
1Great 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.
2Sort 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)0let 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); 3The 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