@hyperfrontend/list-utils§

A tube open at both ends and a cup open only at the top, with the same three numbered discs dropped into each; three pulls take the discs out, the tube from its bottom and the cup from its top, and the exit rows read 1 2 3 under the tube and 3 2 1 beside the cupA tube open at both ends and a cup open only at the top, with the same three numbered discs dropped into each; three pulls take the discs out, the tube from its bottom and the cup from its top, and the exit rows read 1 2 3 under the tube and 3 2 1 beside the cup

Purpose-built collection utilities for queue management, filtering, and iteration patterns.

What is @hyperfrontend/list-utils?

@hyperfrontend/list-utils provides specialized collection utilities focused on common programming patterns that native JavaScript arrays don't handle elegantly. Rather than replicating lodash, this library targets specific use cases: FIFO/LIFO queue management with object reference tracking, cyclical value iteration, and string array sanitization.

The library enforces immutability through frozen interfaces while maintaining high performance. All queue operations (FIFO/LIFO) use native Set for O(1) lookups and guaranteed uniqueness, solving the common problem of accidentally adding duplicate items to task queues or event handlers.

Key Features

Why Use @hyperfrontend/list-utils?

Prevents Queue Bugs in Event-Driven Systems

Native arrays don't enforce uniqueness, making it easy to accidentally register the same event handler, task, or subscription multiple times. Both list kinds reject duplicates based on reference equality, eliminating a common source of memory leaks and duplicate processing in event loops, job queues, and observer patterns. A FIFO list throws on a duplicate push; a LIFO list ignores it.

Simplifies Round-Robin and Cyclical Patterns

The value picker solves the boilerplate problem of cycling through options (load balancer endpoints, color schemes, retry strategies). No manual index tracking or modulo math, just call next(). Particularly useful for testing scenarios where you need predictable value rotation.

Type-Safe String Sanitization

nonEmptyStrings() and uniqueStrings() handle the tedious work of cleaning user input, configuration arrays, or CSV parsing results. Filters null/undefined/empty/whitespace-only values in one call, with full TypeScript type narrowing.

Functional Composition Without Dependencies

All utilities return new arrays or frozen objects, never mutate inputs. This makes them safe for use in React hooks dependencies, Redux reducers, or any pure function context. No lodash required for these specific operations.

Installation

npm install @hyperfrontend/list-utils

Quick Start

import { createFifoList, createValuePicker, nonEmptyStrings, uniqueStrings } from '@hyperfrontend/list-utils'

// FIFO queue for task management
const taskQueue = createFifoList<{ id: string; execute: () => void }>()
taskQueue.push({ id: 'task1', execute: () => console.log('Task 1') })
taskQueue.push({ id: 'task2', execute: () => console.log('Task 2') })
const nextTask = taskQueue.pull() // Gets task1 (first in), or undefined once the queue is drained

// Round-robin value picker
const colorPicker = createValuePicker(['red', 'blue', 'green'])
colorPicker.next() // 'red'
colorPicker.next() // 'blue'
colorPicker.next() // 'green'
colorPicker.next() // 'red' (cycles back)

// String sanitization: blanks are dropped, survivors keep their original padding
const userInputs = ['  hello  ', '', 'world', null, 'hello', '   ', 'world']
const cleaned = uniqueStrings(nonEmptyStrings(userInputs)) // ['  hello  ', 'world', 'hello']

API Overview

Two ordered collections plus a few standalone helpers; the collections are the place to start. createFifoList and createLifoList each take no arguments, are generic over an object type, and return a frozen instance with the same fixed method surface: push, pull, map, forEach, remove, has, size and clear. Choosing one factory over the other decides which end pull() reads from and nothing else about the surrounding code. They diverge on one point, deliberately: pushing an item a FIFO list already holds throws, surfacing a queue that would otherwise take the same job twice, whereas a LIFO list ignores the duplicate and leaves the item where it already was.

Both are backed by a Set of the references you pushed, which has two consequences to know before reaching for either. A primitive is rejected at runtime, not only by the type parameter. And membership is reference identity, so two structurally identical objects are two entries, and has() and remove() want back the exact reference you handed over.

The helpers are independent of the lists and of each other. createValuePicker wraps a non-empty string array in a current() and next() pair that cycles forever, while createRange returns an inclusive run of numbers. For string arrays, nonEmptyStrings drops null, undefined, empty and whitespace-only entries but returns the survivors exactly as they arrived: it tests value.trim(), it does not trim, so padded values come through padded and uniqueStrings then dedupes on exact string equality, which leaves ' hello ' and 'hello' as two distinct results. The last helper, getLastKeyInMap, reads the most recently inserted key of a Map.

Every signature, type parameter and thrown error is in the API reference.

Compatibility

Runs on

  • Node.js>=18.0.0supported
  • Browserssupported
  • Web Workerssupported

Ships as

  • ESMTree-shakeable
  • CJSNode and older bundlers
  • IIFEHyperfrontendListUtils
  • UMDHyperfrontendListUtils

CDN Usage

<!-- unpkg -->
<script src="https://unpkg.com/@hyperfrontend/list-utils"></script>

<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/@hyperfrontend/list-utils"></script>

<script>
  const { createQueue, forEach } = HyperfrontendListUtils
</script>

Global variable: HyperfrontendListUtils

Architecture Highlights§

Both queue kinds hold object references only: pushing a primitive throws at runtime, not just at compile time. Membership is reference identity, so two structurally identical objects are two separate entries, and has() and remove() need the same reference you pushed.

API Reference§

Filter:

ƒFunctions

§function

createFifoList<T>(): FifoList<T>

Creates a FIFO (First-In-First-Out) list.
Returns
FifoList<T>
A FIFO list with methods to manipulate and query the list.
Example

Creating and using FIFO queue

interface Task { id: number; name: string }
const queue = createFifoList<Task>()

queue.push({ id: 1, name: 'first' })
queue.push({ id: 2, name: 'second' })

queue.pull() // => { id: 1, name: 'first' }
queue.pull() // => { id: 2, name: 'second' }
queue.pull() // => undefined (the list is empty)
§function

createLifoList<T>(): LifoList<T>

Creates a LIFO (Last-In-First-Out) list.
Returns
LifoList<T>
A LIFO list with methods to manipulate and query the list.
Example

Creating and using LIFO stack

interface HistoryEntry { url: string; timestamp: number }
const history = createLifoList<HistoryEntry>()

history.push({ url: '/home', timestamp: 1 })
history.push({ url: '/about', timestamp: 2 })

history.pull() // => { url: '/about', timestamp: 2 }
history.pull() // => { url: '/home', timestamp: 1 }
§function

createRange(start: number, end: number): number[]

Creates an array of numbers within a specified range (inclusive).
Parameters
NameTypeDescription
§start
numberThe starting number of the range
§end
numberThe ending number of the range (inclusive)
Returns
number[]
An array containing all numbers from start to end
Example

Generating number ranges

createRange(1, 5)
// => [1, 2, 3, 4, 5]

createRange(3, 3)
// => [3]
§function

createValuePicker(values: string[]): ValuePicker

Creates a value picker that cycles through a list of string values.
Parameters
NameTypeDescription
§values
string[]The array of string values to cycle through
Returns
ValuePicker
A ValuePicker instance with current and next methods
Example

Cycling through values

const colorPicker = createValuePicker(['red', 'green', 'blue'])

colorPicker.current() // => 'red'
colorPicker.next()    // => 'red' (first call initializes)
colorPicker.next()    // => 'green'
colorPicker.next()    // => 'blue'
colorPicker.next()    // => 'red' (cycles back)
§function

getLastKeyInMap<K>(map: Map<K, any>): K

Retrieves the final key from a Map by converting keys to an array.
Parameters
NameTypeDescription
§map
Map<K, any>The Map to extract the last key from
Returns
K
The key that was inserted last, or undefined if map is empty
Example

Getting last key from Map

const userRoles = new Map<string, string>()
userRoles.set('alice', 'admin')
userRoles.set('bob', 'editor')
userRoles.set('charlie', 'viewer')

getLastKeyInMap(userRoles) // => 'charlie'
§function

nonEmptyStrings(values: string[]): string[]

Filters out empty, null, undefined, and whitespace-only strings from an array.
Parameters
NameTypeDescription
§values
string[]The array of strings to filter
Returns
string[]
A new array containing only non-empty strings with content
Example

Filtering empty strings

nonEmptyStrings(['hello', '', '  ', 'world', null as unknown as string])
// => ['hello', 'world']
§function

uniqueStrings(values: string[]): string[]

Removes duplicate strings from an array, preserving insertion order.
Parameters
NameTypeDescription
§values
string[]The array of strings to deduplicate
Returns
string[]
A new array containing only unique strings
Example

Deduplicating strings

uniqueStrings(['apple', 'banana', 'apple', 'cherry', 'banana'])
// => ['apple', 'banana', 'cherry']

◈Interfaces

§interface

FifoList

A FIFO (First-In-First-Out) list interface.
Properties
§interface

LifoList

A LIFO (Last-In-First-Out) list interface.
Properties
§interface

ValuePicker

Interface for cycling through a list of values.
Properties
§current:() => stringReturns the current value without advancing.
§next:() => stringAdvances and returns the next value, cycling at end.

Browse guides filtered to this packageSuggest a guide