Created
May 2, 2025 10:01
-
-
Save z4nr34l/4b12c82841e8ab76aca545f77ea9418e to your computer and use it in GitHub Desktop.
TypeScript smart sorting primitive
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Smart sorting utility that detects data types and applies appropriate sorting methods | |
* - Strings are compared case-insensitively | |
* - Dates are compared as Date objects | |
* - Numbers are compared numerically | |
* - Booleans are compared as booleans (false first, true second) | |
*/ | |
/** | |
* Detects the data type of a value | |
*/ | |
export function detectDataType( | |
value: unknown, | |
): "string" | "number" | "date" | "boolean" | "other" { | |
if (value === null || value === undefined) { | |
return "other"; | |
} | |
if (typeof value === "boolean") { | |
return "boolean"; | |
} | |
if (typeof value === "number" && !isNaN(value)) { | |
return "number"; | |
} | |
if (typeof value === "string") { | |
// Check if it's a valid date string | |
const date = new Date(value); | |
// Ensure it's a valid date format (not "Invalid Date") and contains dashes or slashes suggesting date format | |
if ( | |
!isNaN(date.getTime()) && | |
(value.includes("-") || value.includes("/") || value.includes("T")) | |
) { | |
return "date"; | |
} | |
// Check if it's a numeric string | |
if (/^-?\d+(\.\d+)?$/.test(value.trim())) { | |
return "number"; | |
} | |
return "string"; | |
} | |
return "other"; | |
} | |
/** | |
* Compares two values based on their detected data types | |
*/ | |
export function smartCompare( | |
a: unknown, | |
b: unknown, | |
order: "asc" | "desc" = "asc", | |
): number { | |
// Determine if values are null/undefined for special handling | |
const aIsNullish = a === null || a === undefined; | |
const bIsNullish = b === null || b === undefined; | |
// Handle null/undefined values (always push them to the end) | |
if (aIsNullish && bIsNullish) return 0; | |
if (aIsNullish) return order === "asc" ? 1 : -1; | |
if (bIsNullish) return order === "asc" ? -1 : 1; | |
// Detect data types | |
const typeA = detectDataType(a); | |
const typeB = detectDataType(b); | |
// If types differ, sort by type hierarchy (string < number < date < boolean < other) | |
if (typeA !== typeB) { | |
const typeHierarchy = { | |
string: 1, | |
number: 2, | |
date: 3, | |
boolean: 4, | |
other: 5, | |
}; | |
const result = typeHierarchy[typeA] - typeHierarchy[typeB]; | |
return order === "asc" ? result : -result; | |
} | |
// Compare values based on their common type | |
let result = 0; | |
switch (typeA) { | |
case "string": | |
result = String(a).localeCompare(String(b), undefined, { | |
sensitivity: "base", | |
}); | |
break; | |
case "number": | |
// Convert to numbers in case they are numeric strings | |
result = Number(a) - Number(b); | |
break; | |
case "date": | |
result = | |
new Date(a as string).getTime() - new Date(b as string).getTime(); | |
break; | |
case "boolean": | |
result = a === b ? 0 : a ? 1 : -1; | |
break; | |
default: | |
// For other types, convert to string and compare | |
result = String(a).localeCompare(String(b)); | |
} | |
return order === "asc" ? result : -result; | |
} | |
/** | |
* Smart sort function that can be used to sort arrays of objects | |
* @param data The array of objects to sort | |
* @param column The column/key to sort by | |
* @param order The sort order ('asc' or 'desc') | |
* @returns A new sorted array | |
*/ | |
export function smartSort<T>( | |
data: readonly T[], | |
column: keyof T | string, | |
order: "asc" | "desc" = "asc", | |
): T[] { | |
return [...data].sort((a, b) => { | |
// Handle cases where the column might not exist on some items | |
const aValue = | |
a === null || a === undefined | |
? undefined | |
: typeof a === "object" | |
? (a as any)[column] | |
: undefined; | |
const bValue = | |
b === null || b === undefined | |
? undefined | |
: typeof b === "object" | |
? (b as any)[column] | |
: undefined; | |
return smartCompare(aValue, bValue, order); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment