Why I Built data-structure-typed: A Modern Data Structures Library for TypeScript
TL;DR: After years of using various data structure libraries in JavaScript/TypeScript, I built one that prioritizes type safety, native API familiarity, and performance. Here's what I learned.
The Problem
If you've worked on algorithm-heavy TypeScript projects, you've probably faced this dilemma:
-
Native JS only gives you
Array,Map,Set, andObject— no trees, no heaps, no graphs - Existing libraries often have inconsistent APIs, poor TypeScript support, or expose too many internals
I wanted something that felt like a natural extension of JavaScript's built-in collections — with the same API patterns, full type safety, and solid performance.
What is data-structure-typed?
It's a comprehensive collection of data structures for JavaScript and TypeScript:
- Binary Trees: BST, AVL Tree, Red-Black Tree, TreeMap, TreeSet
- Heaps: Min/Max Heap, Priority Queue
- Graphs: Directed, Undirected (with Dijkstra, Bellman-Ford, Floyd-Warshall, etc.)
- Linear: Queue, Deque, Stack, Singly/Doubly Linked List
- Others: Trie, HashMap, and more
Design Philosophy
1. Native API Familiarity
If you know JavaScript's Map and Set, you already know how to use TreeMap and TreeSet:
import { TreeMap, TreeSet } from 'data-structure-typed';
// Works just like native Map, but keys are always sorted
const map = new TreeMap<string, number>();
map.set('banana', 3);
map.set('apple', 1);
map.set('cherry', 2);
console.log([...map.keys()]); // ['apple', 'banana', 'cherry'] - sorted!
// Works just like native Set, but elements are always sorted
const set = new TreeSet<number>([3, 1, 4, 1, 5, 9, 2, 6]);
console.log([...set]); // [1, 2, 3, 4, 5, 6, 9] - sorted & deduplicated!
2. Full TypeScript Support
Everything is fully typed with generics. No any types leaking through:
interface User {
id: number;
name: string;
score: number;
}
// Type-safe priority queue
const leaderboard = new MaxPriorityQueue<User>({
comparator: (a, b) => a.score - b.score
});
leaderboard.add({ id: 1, name: 'Alice', score: 100 });
leaderboard.add({ id: 2, name: 'Bob', score: 150 });
const top = leaderboard.poll(); // Type: User | undefined
console.log(top?.name); // 'Bob'
3. Navigation Methods (Java-style)
TreeMap and TreeSet include Java's NavigableMap/NavigableSet methods:
const prices = new TreeMap<number, string>([
[10, 'cheap'],
[50, 'medium'],
[100, 'expensive'],
[500, 'luxury']
]);
prices.floor(75); // [50, 'medium'] - largest key ≤ 75
prices.ceiling(75); // [100, 'expensive'] - smallest key ≥ 75
prices.lower(50); // [10, 'cheap'] - largest key < 50
prices.higher(50); // [100, 'expensive'] - smallest key > 50
4. Functional Methods
All collections support map, filter, reduce, forEach:
const numbers = new TreeSet([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
const evens = numbers.filter(n => n % 2 === 0);
console.log([...evens]); // [2, 4, 6, 8, 10]
const doubled = numbers.map(n => n * 2);
console.log([...doubled]); // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Performance
Under the hood, TreeMap and TreeSet use Red-Black Trees. Here's how they compare to the popular js-sdsl library:
| Operation | data-structure-typed | js-sdsl |
|---|---|---|
| set (100K) | 1.00x | 1.54x slower |
| get (100K) | 1.00x | 1.02x |
| delete (100K) | 1.22x | 1.00x |
| iterate (100K) | 1.00x | 2.15x slower |
Benchmarks run on Node.js 22, Apple M1
The key win is iteration — we're 2x faster because we use an optimized iterator implementation.
Real-World Use Cases
LeetCode / Competitive Programming
// LeetCode 729: My Calendar I
class MyCalendar {
private bookings = new TreeMap<number, number>();
book(start: number, end: number): boolean {
const prev = this.bookings.floor(start);
const next = this.bookings.ceiling(start);
if (prev && prev[1] > start) return false;
if (next && next[0] < end) return false;
this.bookings.set(start, end);
return true;
}
}
Task Scheduling
const taskQueue = new MinPriorityQueue<Task>({
comparator: (a, b) => a.priority - b.priority
});
// Add tasks
taskQueue.add({ id: 1, priority: 3, name: 'Low priority' });
taskQueue.add({ id: 2, priority: 1, name: 'Urgent!' });
taskQueue.add({ id: 3, priority: 2, name: 'Medium' });
// Process in priority order
while (!taskQueue.isEmpty()) {
const task = taskQueue.poll()!;
console.log(`Processing: ${task.name}`);
}
// Output: Urgent! → Medium → Low priority
Graph Algorithms
const graph = new DirectedGraph<string, number>();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addEdge('A', 'B', 1);
graph.addEdge('B', 'C', 2);
graph.addEdge('A', 'C', 5);
const { distMap } = graph.dijkstra('A');
console.log(distMap.get('C')); // 3 (A→B→C is shorter than A→C)
Installation
npm install data-structure-typed
Or install individual packages for smaller bundles:
npm install tree-map-typed # Just TreeMap
npm install heap-typed # Just Heap/PriorityQueue
What's Next?
- Performance improvements (we're always benchmarking)
- More LeetCode-style examples in docs
- Interactive playground
Links
- GitHub: https://github.com/zrwusa/data-structure-typed
- npm: https://www.npmjs.com/package/data-structure-typed
- Docs: https://data-structure-typed-docs.vercel.app
If you're working on anything that needs proper data structures in TypeScript, give it a try. PRs and issues welcome!
What data structures do you wish JavaScript had natively? Let me know in the comments!
Top comments (0)