Skip to content

Commit

Permalink
feat: handle null and undefined values correctly without erroring
Browse files Browse the repository at this point in the history
  • Loading branch information
jvandenaardweg committed Nov 8, 2022
1 parent 9438046 commit 1e8c726
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 1 deletion.
80 changes: 80 additions & 0 deletions src/sort-by.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
Expand Down Expand Up @@ -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);
});
});
});
16 changes: 15 additions & 1 deletion src/sort-by.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -10,6 +11,7 @@ export type SortByDirection = 'asc' | 'desc';
*/
export function sortBy<T>(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)) {
Expand Down Expand Up @@ -67,6 +69,18 @@ export function sortBy<T>(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,
Expand All @@ -85,7 +99,7 @@ export type PathOfString<T, P extends string = ''> = {
? PathOfString<T[K], `${P}${K}.`> 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<T[K][number], `${P}${K}.`> extends infer S
Expand Down
6 changes: 6 additions & 0 deletions src/utils/null.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Checks if `value` is `null` or `undefined`.
*/
export function isNil<T>(value?: T | null): value is null | undefined {
return value === null || value === undefined;
}

0 comments on commit 1e8c726

Please sign in to comment.