A simple and powerful sortby implementation in TypeScript.
npm install @hyldmo/byA tiny, powerful sorting utility for arrays of objects in TypeScript and JavaScript. @hyldmo/by provides a flexible and intuitive way to sort complex data structures.
- Type-Safe: Written in TypeScript for robust type checking.
- Flexible Selectors: Sort by property keys, nested paths, or custom accessor functions.
- Multi-Criteria Sorting: Easily define multiple sorting rules with different orders.
- Intuitive API: A single function by that is easy to learn and use.
- Handles Complex Types: Properly sorts strings, numbers, booleans, Dates, arrays (by length), and handles null/undefined values gracefully.
``bash`
yarn add @hyldmo/by
or
`bash`
npm install @hyldmo/by
Import the by function and use it with Array.prototype.sort.
`typescript
import { by } from '@hyldmo/by'
const users = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 30 }
]
// Sort by name alphabetically
users.sort(by('name'))
// => [ { name: 'Alice', ... }, { name: 'Bob', ... }, { name: 'Charlie', ... } ]
`
Use the Order enum for ascending or descending order.
`typescript
import { by, Order } from '@hyldmo/by'
// Sort by age in descending order
users.sort(by('age', Order.Desc))
// => [ { name: 'Alice', age: 30 }, { name: 'Charlie', age: 30 }, { name: 'Bob', age: 25 } ]
`
Use dot-path strings to sort by nested properties. Paths are type-safe via type-fest Paths.
`typescript
const users = [
{ name: 'Alice', address: { city: 'New York' } },
{ name: 'Bob', address: { city: 'Los Angeles' } },
{ name: 'Charlie', address: { city: 'Chicago' } }
]
users.sort(by('address.city'))
// => [ { name: 'Charlie', ... }, { name: 'Bob', ... }, { name: 'Alice', ... } ]
`
Provide a function to sort by a derived value (e.g., name length, case-insensitive key, normalized text). Dates are already supported without a custom selector.
`typescript
const users = [
{ name: 'Alice' },
{ name: 'Bob' },
{ name: 'Charlie' }
]
// Sort by name length (shortest first)
users.sort(by(u => u.name.length))
// => [ { name: 'Bob' }, { name: 'Alice' }, { name: 'Charlie' } ]
// Case-insensitive name sort using a normalized key
users.sort(by(u => u.name.toLocaleLowerCase()))
`
Pass an array of selectors to sort by multiple properties. Earlier selectors have higher priority. Optionally pass a single Order that applies to all selectors.
`typescript
import { by, Order } from '@hyldmo/by'
const users = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 30 }
]
// 1) by age descending, 2) then by name descending
users.sort(by(['age', 'name'], Order.Desc))
// => [ { name: 'Charlie', age: 30 }, { name: 'Alice', age: 30 }, { name: 'Bob', age: 25 } ]
// Multiple selectors evaluated in order
users.sort(by(['age', 'name']))
`
Array properties are automatically sorted by their length.
`typescript
const posts = [
{ title: 'Post A', tags: ['js', 'ts', 'react'] },
{ title: 'Post B', tags: ['python'] },
{ title: 'Post C', tags: ['go', 'rust'] }
]
posts.sort(by('tags'))
// => [ { title: 'Post B', tags: ['python'] }, { title: 'Post C', ... }, { title: 'Post A', ... } ]
`
null and undefined values are sorted to the beginning in ascending order, and to the end in descending order.
`typescript
const items = [{ value: 10 }, { value: null }, { value: 5 }]
items.sort(by('value'))
// => [ { value: null }, { value: 5 }, { value: 10 } ]
import { Order } from '@hyldmo/by'
items.sort(by('value', Order.Desc))
// => [ { value: 10 }, { value: 5 }, { value: null } ]
`
The comparator automatically handles: string, number, boolean, Date, and arrays (by length). null/undefined are sorted to the beginning in ascending order and to the end in descending order. Use a custom selector only for derived values or normalization.
- selector: SelectorT
- A property path of (supports dot-paths via Paths).order
- A function that receives an object and returns a sortable value.
- : Order (optional, defaults to Order.Asc)
- selectors: Selectororder
- An array of selectors evaluated in order until a difference is found.
- : Order (optional, defaults to Order.Asc)
`ts
import type { Paths } from 'type-fest'
export enum Order {
Asc = 1,
Desc = -1
}
export type Selector
| Paths
| ((obj: T) => string | number | Date | null | undefined | boolean | unknown[])
``