diff --git a/src/sort-by.test.ts b/src/sort-by.test.ts index 73f88fe..3fe73f2 100644 --- a/src/sort-by.test.ts +++ b/src/sort-by.test.ts @@ -50,6 +50,54 @@ describe('arrays', () => { expect(result).toEqual(expected); }); + it('should sort undefined values in an number array ascending', () => { + const array = [3, undefined, 1]; + const result = [...array].sort(sortBy('asc')); + const expected = [1, 3, undefined]; + + expect(result).toEqual(expected); + }); + + it('should sort undefined values in an number array descending', () => { + const array = [1, undefined, 3]; + const result = [...array].sort(sortBy('desc')); + const expected = [3, 1, undefined]; + + expect(result).toEqual(expected); + }); + + it('should sort null values in an number array ascending', () => { + const array = [3, null, 1]; + const result = [...array].sort(sortBy('asc')); + const expected = [1, 3, null]; + + expect(result).toEqual(expected); + }); + + it('should sort null values in an number array descending', () => { + const array = [1, null, 3]; + const result = [...array].sort(sortBy('desc')); + const expected = [3, 1, null]; + + expect(result).toEqual(expected); + }); + + it('should sort undefined values in an number array ascending', () => { + const array = [3, undefined, 1]; + const result = [...array].sort(sortBy('asc')); + const expected = [1, 3, undefined]; + + expect(result).toEqual(expected); + }); + + it('should sort undefined values in an number array descending', () => { + const array = [1, undefined, 3]; + const result = [...array].sort(sortBy('desc')); + const expected = [3, 1, undefined]; + + expect(result).toEqual(expected); + }); + it('should error when all array items are not from the same type while sorting descending', () => { const array = [1, '2', 3]; const resultFn = () => [...array].sort(sortBy('desc')); @@ -362,5 +410,37 @@ describe('arrays', () => { expect(result).toEqual(expected); }); + + it('should sort an array ascending by the id property with null values', () => { + const array = [{ id: 3 }, { id: null }, { id: 1 }]; + const result = [...array].sort(sortByProperty('id', 'asc')); + const expected = [{ id: 1 }, { id: 3 }, { id: null }]; + + expect(result).toEqual(expected); + }); + + it('should sort an array descending by the id property with null values', () => { + const array = [{ id: 1 }, { id: null }, { id: 3 }]; + const result = [...array].sort(sortByProperty('id', 'desc')); + const expected = [{ id: 3 }, { id: 1 }, { id: null }]; + + expect(result).toEqual(expected); + }); + + it('should sort an array ascending by the id property with null values', () => { + const array = [{ id: 3 }, { id: undefined }, { id: 1 }]; + const result = [...array].sort(sortByProperty('id', 'asc')); + const expected = [{ id: 1 }, { id: 3 }, { id: undefined }]; + + expect(result).toEqual(expected); + }); + + it('should sort an array descending by the id property with undefined values', () => { + const array = [{ id: 1 }, { id: undefined }, { id: 3 }]; + const result = [...array].sort(sortByProperty('id', 'desc')); + const expected = [{ id: 3 }, { id: 1 }, { id: undefined }]; + + expect(result).toEqual(expected); + }); }); }); diff --git a/src/sort-by.ts b/src/sort-by.ts index e0fa57a..fdf29f6 100644 --- a/src/sort-by.ts +++ b/src/sort-by.ts @@ -2,6 +2,7 @@ import { isDate } from '@/utils/date'; import { isString } from '@/utils/string'; import { isNumber } from '@/utils/number'; import { isArray } from '@/utils/array'; +import { isNil } from './utils/null'; export type SortByDirection = 'asc' | 'desc'; @@ -10,6 +11,7 @@ export type SortByDirection = 'asc' | 'desc'; */ export function sortBy(direction: SortByDirection) { return (a: T, b: T): number => { + // console.log('a', a, 'b', b); if (direction === 'asc') { // number asc (a -> b) if (isNumber(a) && isNumber(b)) { @@ -67,6 +69,18 @@ export function sortBy(direction: SortByDirection) { .localeCompare(a.sort(sortBy(direction)).toString()); } + // if a is null or undefined and b is not, a is greater than b + // moving the item to the end of the array + if (isNil(a) && b) { + return 1; + } + + // if b is null or undefined and a is not, a is less than b + // moving the item to the end of the array + if (a && isNil(b)) { + return -1; + } + throw new Error( `Can't sort, typeof a (${typeof a}: ${JSON.stringify( a, @@ -85,7 +99,7 @@ export type PathOfString = { ? PathOfString extends infer S ? `${S & string}` : never - : T[K] extends number | number[] | string | string[] | Date | Date[] + : T[K] extends number | number[] | string | string[] | Date | Date[] | null | undefined ? `${P}${K}` : T[K] extends unknown[] ? PathOfString extends infer S diff --git a/src/utils/null.ts b/src/utils/null.ts new file mode 100644 index 0000000..2fcf55a --- /dev/null +++ b/src/utils/null.ts @@ -0,0 +1,6 @@ +/** + * Checks if `value` is `null` or `undefined`. + */ +export function isNil(value?: T | null): value is null | undefined { + return value === null || value === undefined; +}