High-performance doubly-linked list implementation with bidirectional operations and array-like methods
npx @tessl/cli install tessl/npm-yallist@5.0.0Yallist (Yet Another Linked List) is a high-performance doubly-linked list implementation for JavaScript and TypeScript. It provides array-like operations optimized for frequent insertions and deletions at arbitrary positions, with comprehensive bidirectional iteration capabilities.
npm install yallistimport { Yallist, Node } from "yallist";For CommonJS:
const { Yallist, Node } = require("yallist");import { Yallist } from "yallist";
// Create a new list from an array
const list = new Yallist([1, 2, 3]);
// Add elements
list.push(4, 5); // Add to tail
list.unshift(0); // Add to head
// Access elements
console.log(list.get(0)); // 0 (from head)
console.log(list.getReverse(0)); // 5 (from tail)
// Iterate
list.forEach((value, index) => console.log(value));
list.forEachReverse((value, index) => console.log(value));
// Transform data
const doubled = list.map(x => x * 2);
const sum = list.reduce((acc, val) => acc + val, 0);
// Convert to array
console.log(list.toArray()); // [0, 1, 2, 3, 4, 5]Yallist consists of two main classes:
Create and initialize linked lists from iterables or using factory methods.
/**
* Main doubly-linked list class with generic type support
*/
class Yallist<T = unknown> {
/** First node in the list */
head?: Node<T>;
/** Last node in the list */
tail?: Node<T>;
/** Number of nodes in the list */
length: number;
/**
* Create a new list from an iterable
* @param list - Iterable to initialize the list from
*/
constructor(list?: Iterable<T>);
/**
* Factory method to create a new list
* @param list - Iterable to initialize the list from
* @returns New Yallist instance
*/
static create<T = unknown>(list?: Iterable<T>): Yallist<T>;
}Retrieve values by position from either end of the list.
/**
* Get the value at position n from the head
* @param n - Index from head (0-based)
* @returns Value at position or undefined if out of bounds
*/
get(n: number): T | undefined;
/**
* Get the value at position n from the tail
* @param n - Index from tail (0-based)
* @returns Value at position or undefined if out of bounds
*/
getReverse(n: number): T | undefined;Add elements to the head or tail of the list.
/**
* Add elements to the tail of the list
* @param args - Elements to add
* @returns New length of the list
*/
push(...args: T[]): number;
/**
* Add elements to the head of the list
* @param args - Elements to add
* @returns New length of the list
*/
unshift(...args: T[]): number;Remove and return elements from either end of the list.
/**
* Remove and return the tail element
* @returns Tail value or undefined if list is empty
*/
pop(): T | undefined;
/**
* Remove and return the head element
* @returns Head value or undefined if list is empty
*/
shift(): T | undefined;Direct manipulation of Node objects for advanced use cases.
/**
* Remove a specific node from the list
* @param node - Node to remove (must belong to this list)
* @returns Next node after the removed node, or undefined if removing tail
* @throws Error with message "removing node which does not belong to this list"
*/
removeNode(node: Node<T>): Node<T> | undefined;
/**
* Move a node to the head of the list
* @param node - Node to move (will be removed from its current list if any)
*/
unshiftNode(node: Node<T>): void;
/**
* Move a node to the tail of the list
* @param node - Node to move (will be removed from its current list if any)
*/
pushNode(node: Node<T>): void;Iterate through the list in either direction with callback functions.
/**
* Execute a function for each element from head to tail
* @param fn - Function to execute for each element (receives value, index, and list)
* @param thisp - Value to use as 'this' when executing fn (optional)
*/
forEach(fn: (value: T, index: number, list: Yallist<T>) => any, thisp?: any): void;
/**
* Execute a function for each element from tail to head
* @param fn - Function to execute for each element (receives value, index, and list)
* @param thisp - Value to use as 'this' when executing fn (optional)
*/
forEachReverse(fn: (value: T, index: number, list: Yallist<T>) => any, thisp?: any): void;
/**
* Make the list iterable (head to tail)
* @returns Iterator that yields values from head to tail
*/
[Symbol.iterator](): IterableIterator<T>;Create new lists by transforming elements while preserving the list structure.
/**
* Create a new list with transformed values (head to tail)
* @param fn - Transformation function (receives value and list)
* @param thisp - Value to use as 'this' when executing fn (optional)
* @returns New Yallist with transformed values
*/
map<R = any>(fn: (value: T, list: Yallist<T>) => R, thisp?: any): Yallist<R>;
/**
* Create a new list with transformed values (tail to head)
* @param fn - Transformation function (receives value and list)
* @param thisp - Value to use as 'this' when executing fn (optional)
* @returns New Yallist with transformed values
*/
mapReverse<R = any>(fn: (value: T, list: Yallist<T>) => R, thisp?: any): Yallist<R>;Reduce the list to a single value using accumulator functions.
/**
* Reduce list to single value without initial value (head to tail)
* @param fn - Reducer function
* @returns Reduced value
* @throws TypeError with message "Reduce of empty list with no initial value"
*/
reduce(fn: (left: T, right: T, index: number) => T): T;
/**
* Reduce list to single value with initial value (head to tail)
* @param fn - Reducer function
* @param initial - Initial accumulator value
* @returns Reduced value
*/
reduce<R = any>(fn: (acc: R, next: T, index: number) => R, initial: R): R;
/**
* Reduce list to single value without initial value (tail to head)
* @param fn - Reducer function
* @returns Reduced value
* @throws TypeError with message "Reduce of empty list with no initial value"
*/
reduceReverse(fn: (left: T, right: T, index: number) => T): T;
/**
* Reduce list to single value with initial value (tail to head)
* @param fn - Reducer function
* @param initial - Initial accumulator value
* @returns Reduced value
*/
reduceReverse<R = any>(fn: (acc: R, next: T, index: number) => R, initial: R): R;Convert the list to standard JavaScript arrays in either direction.
/**
* Convert list to array from head to tail
* @returns Array containing all list values
*/
toArray(): T[];
/**
* Convert list to array from tail to head
* @returns Array containing all list values in reverse order
*/
toArrayReverse(): T[];Extract portions of the list as new Yallist instances.
/**
* Extract a slice of the list (head to tail)
* @param from - Start index (inclusive, default 0)
* @param to - End index (exclusive, default list.length)
* @returns New Yallist containing the slice
*/
slice(from?: number, to?: number): Yallist<T>;
/**
* Extract a slice of the list (tail to head)
* @param from - Start index (inclusive, default 0)
* @param to - End index (exclusive, default list.length)
* @returns New Yallist containing the slice in reverse order
*/
sliceReverse(from?: number, to?: number): Yallist<T>;Modify the list by removing/inserting elements at arbitrary positions.
/**
* Remove elements and/or insert new elements at a specific position
* @param start - Start index for modification (negative indices count from end)
* @param deleteCount - Number of elements to remove (default 0)
* @param nodes - New elements to insert at the start position
* @returns Array of removed elements
*/
splice(start: number, deleteCount?: number, ...nodes: T[]): T[];
/**
* Reverse the list in place
* @returns This list (for chaining)
*/
reverse(): Yallist<T>;/**
* Individual node in the doubly-linked list
*/
class Node<T = unknown> {
/** The data stored in this node */
value: T;
/** Reference to the next node in the list */
next?: Node<T>;
/** Reference to the previous node in the list */
prev?: Node<T>;
/** Reference to the list this node belongs to */
list?: Yallist<T>;
/**
* Create a new node
* @param value - The value to store in the node
* @param prev - Previous node reference
* @param next - Next node reference
* @param list - List this node belongs to
*/
constructor(
value: T,
prev?: Node<T>,
next?: Node<T>,
list?: Yallist<T>
);
}