DEV Community

Cover image for data-structure-typed: A Modern Data Structures Library for TypeScript
Ruiwen Zeng
Ruiwen Zeng

Posted on

data-structure-typed: A Modern Data Structures Library for TypeScript

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, and Object — 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!
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Installation

npm install data-structure-typed
Enter fullscreen mode Exit fullscreen mode

Or install individual packages for smaller bundles:

npm install tree-map-typed    # Just TreeMap
npm install heap-typed        # Just Heap/PriorityQueue
Enter fullscreen mode Exit fullscreen mode

What's Next?

  • Performance improvements (we're always benchmarking)
  • More LeetCode-style examples in docs
  • Interactive playground

Links


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)