Skip to content

Karelaking/ts-collections

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

ts-collections

A robust, type-safe collections framework for TypeScript

License: MIT TypeScript npm version Vitest Visitors

FeaturesQuick StartAPI OverviewDocumentationContributing


🌟 Why ts-collections?

ts-collections is a Java-inspired collections framework and library that brings enterprise-grade data structures to TypeScript. Built with modern TypeScript features, it provides automatic type safety, familiar APIs for Java developers, and zero-configuration setup.

import { ArrayList, HashMap, HashSet } from "ts-collections";

// Automatic type safety - no configuration needed!
const list = new ArrayList<number>();
list.add(42); // ✅ Works
list.add("text" as any); // ❌ Runtime error (caught automatically)

// Familiar Java-style APIs
const map = new HashMap<string, User>();
map.put("john", user);
const value = map.get("john");

// Complete type inference
const set = new HashSet<string>();
set.add("unique");

✨ Features

🔒 Automatic Type Safety

Runtime type checking enabled by default - no configuration needed. Works just like Java's type-safe collections.

🎯 Zero Configuration

Type safety works out of the box. No need to learn validation libraries or configure schemas.

☕ Java-Friendly

Familiar Collections interface for Java developers. If you know Java Collections, you already know ts-collections.

🏗️ Extensible Architecture

Easy to create custom implementations through abstract base classes and clear interfaces.

📊 Performance Transparency

All operations documented with time/space complexity (O-notation).

✅ Battle-Tested

332/332 tests passing. Comprehensive test coverage for all implementations.

Coming from Java?

You'll feel right at home! Type safety works exactly like Java:

// Java
List<Integer> list = new ArrayList<>();
list.add(1);
list.add("text"); // ❌ Compile error

// TypeScript with ts-collections
const list = new ArrayList<number>();
list.add(1);
list.add("text" as any); // ❌ Runtime error (automatic!)

📖 Java Migration Guide →

📚 API Overview

Core Interfaces

Interface Description Key Methods
Collection<E> Base interface for all collections add(), remove(), size(), contains()
List<E> Ordered, indexed collection get(), set(), indexOf(), subList()
Set<E> Unique elements, no duplicates Inherits Collection with uniqueness
Map<K,V> Key-value associations put(), get(), containsKey(), entries()
Queue<E> FIFO processing offer(), poll(), peek()

Available Implementations

Type Implementation Characteristics
List ArrayList<E> Dynamic array, fast random access O(1)
List LinkedList<E> Doubly-linked, fast insertion/deletion
Set HashSet<E> Hash table, fast lookup O(1) average
Set TreeSet<E> Sorted set, comparator-based ordering
Map HashMap<K,V> Hash table, fast key lookup O(1) average
Map TreeMap<K,V> Sorted map, comparator-based ordering
Queue LinkedQueue<E> Linked list, FIFO operations O(1)
Queue PriorityQueue<E> Heap-based priority ordering
Deque LinkedDeque<E> Double-ended queue, add/remove at both ends

Architecture

graph TD
    A[Collection Interface] --> B[List]
    A --> C[Set]
    A --> D[Queue]
    E[Map Interface] --> F[HashMap]
    B --> G[ArrayList]
    B --> H[LinkedList]
    C --> I[HashSet]
    D --> J[LinkedQueue]
Loading

📦 Installation

npm i @karelaking/ts-collections
pnpm i @karelaking/ts-collections
Other package managers
# Using pnpm
pnpm add ts-collections

# Using yarn
yarn add ts-collections

🚀 Quick Start

Lists - Ordered Collections

import { ArrayList } from "ts-collections";

const list = new ArrayList<number>();
list.add(10);
list.add(20);
list.add(30);

console.log(list.get(0)); // 10
console.log(list.size()); // 3
list.removeAt(1); // [10, 30]

Sets - Unique Elements

import { HashSet } from "ts-collections";

const set = new HashSet<string>();
set.add("apple");
set.add("banana");
set.add("apple"); // Duplicate ignored

console.log(set.size()); // 2
console.log(set.contains("apple")); // true

Maps - Key-Value Pairs

import { HashMap } from "ts-collections";

const map = new HashMap<string, number>();
map.put("Alice", 25);
map.put("Bob", 30);

console.log(map.get("Alice")); // 25
console.log(map.containsKey("Bob")); // true

Queues - FIFO Processing

import { LinkedQueue } from "ts-collections";

const queue = new LinkedQueue<string>();
queue.offer("Task 1");
queue.offer("Task 2");

console.log(queue.poll()); // "Task 1"
console.log(queue.peek()); // "Task 2"

Iterators - Traverse Elements

import { ArrayList } from "ts-collections";

const list = new ArrayList<number>();
list.add(1);
list.add(2);
list.add(3);

const iterator = list.iterator();
while (iterator.hasNext()) {
  console.log(iterator.next());
}

Priority Queues - Sorted Processing

import { PriorityQueue } from "ts-collections";

const priorities = new PriorityQueue<number>();
priorities.offer(5);
priorities.offer(1);
priorities.offer(3);

console.log(priorities.poll()); // 1
console.log(priorities.peek()); // 3

Tree Maps - Sorted Key Order

import { TreeMap } from "ts-collections";

const sortedMap = new TreeMap<string, number>();
sortedMap.put("c", 3);
sortedMap.put("a", 1);
sortedMap.put("b", 2);

console.log(sortedMap.keys()); // ["a", "b", "c"]

Tree Sets - Sorted Unique Values

import { TreeSet } from "ts-collections";

const sortedSet = new TreeSet<number>();
sortedSet.add(3);
sortedSet.add(1);
sortedSet.add(2);

console.log(sortedSet.toArray()); // [1, 2, 3]

Double-Ended Queues - Front and Back Operations

import { LinkedDeque } from "ts-collections";

const deque = new LinkedDeque<string>();
deque.addFirst("middle");
deque.addFirst("front");
deque.addLast("back");

console.log(deque.pollFirst()); // "front"
console.log(deque.pollLast()); // "back"

💡 Common Use Cases

Shopping Cart Example
import { ArrayList } from "ts-collections";

interface Product {
  id: string;
  name: string;
  price: number;
}

class ShoppingCart {
  private items = new ArrayList<Product>();

  addItem(product: Product): void {
    this.items.add(product);
  }

  getTotalPrice(): number {
    return this.items.toArray().reduce((sum, item) => sum + item.price, 0);
  }
}

const cart = new ShoppingCart();
cart.addItem({ id: "1", name: "Laptop", price: 999 });
console.log(cart.getTotalPrice()); // 999
Session Management with Maps
import { HashMap } from "ts-collections";

interface Session {
  userId: string;
  loginTime: Date;
}

class SessionManager {
  private sessions = new HashMap<string, Session>();

  createSession(userId: string): string {
    const sessionId = this.generateId();
    this.sessions.put(sessionId, { userId, loginTime: new Date() });
    return sessionId;
  }

  getSession(sessionId: string): Session | undefined {
    return this.sessions.get(sessionId);
  }
}
Task Queue Processing
import { LinkedQueue } from "ts-collections";

const taskQueue = new LinkedQueue<string>();

// Add tasks
taskQueue.offer("Process payment");
taskQueue.offer("Send email");
taskQueue.offer("Update inventory");

// Process tasks
while (taskQueue.size() > 0) {
  const task = taskQueue.poll();
  console.log(`Processing: ${task}`);
}
Unique Tags with Sets
import { HashSet } from "ts-collections";

class TagManager {
  private tags = new HashSet<string>();

  addTag(tag: string): boolean {
    return this.tags.add(tag.toLowerCase());
  }

  getTags(): string[] {
    return this.tags.toArray().sort();
  }
}

const tags = new TagManager();
tags.addTag("JavaScript");
tags.addTag("TypeScript");
tags.addTag("javascript"); // Duplicate ignored
console.log(tags.getTags()); // ["javascript", "typescript"]

Advanced: Custom Validation with Zod (Optional)

import { ArrayList } from "ts-collections";
import { z } from "zod";

// Advanced validation for power users
const strictNumbers = new ArrayList<number>({
  schema: z.number().positive().int(),
});

strictNumbers.add(5); // ✅ OK
strictNumbers.add(-1 as any); // ❌ ERROR: must be positive
strictNumbers.add(3.14 as any); // ❌ ERROR: must be integer

Note: Zod is optional - basic type safety works automatically without it!

🏗️ Design Principles

ts-collections follows SOLID principles for maintainable, extensible code:

  • Single Responsibility: Each class has one clear purpose
  • Open/Closed: Extend through abstract classes without modifying existing code
  • Liskov Substitution: Subclasses work anywhere their parent class works
  • Interface Segregation: Clean, focused interfaces
  • Dependency Inversion: Depend on abstractions, not concrete implementations

Building Custom Collections

Extend abstract base classes to create your own data structures:

import { AbstractList } from "ts-collections";

class CustomList<E> extends AbstractList<E> {
  private elements: E[] = [];

  size(): number {
    return this.elements.length;
  }

  get(index: number): E {
    if (index < 0 || index >= this.size()) {
      throw new Error("Index out of bounds");
    }
    return this.elements[index];
  }

  // Implement remaining abstract methods...
}

📖 Documentation

Quick References

API Documentation

Generate full API docs with TypeDoc:

pnpm docs

🧪 Testing

All implementations have comprehensive test coverage (332/332 tests passing).

Test files live under the test/ directory and mirror the src/ structure.

# Run all tests
pnpm test

# Watch mode
pnpm test --watch

# With coverage
pnpm test --coverage

🤝 Contributing

We welcome contributions! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes
  4. Test your changes: pnpm test
  5. Lint your code: pnpm lint
  6. Commit with clear messages
  7. Push to your branch
  8. Open a Pull Request

Development Setup

# Clone and install
git clone https://github.com/Karelaking/ts-collections.git
cd ts-collections
pnpm install

# Development workflow
pnpm test          # Run tests
pnpm lint          # Check code style
pnpm build         # Build the project
pnpm docs          # Generate documentation

For detailed guidelines, see CONTRIBUTING.md.

Examples

Check out runnable examples in the examples folder.

📊 Performance

All data structures document their performance characteristics:

Operation ArrayList HashSet HashMap LinkedQueue
Add/Put O(1)* O(1)* O(1)* O(1)
Get O(1) - O(1)* -
Remove O(n) O(1)* O(1)* O(1)
Contains O(n) O(1)* O(1)* O(n)
Size O(1) O(1) O(1) O(1)

* amortized time complexity

Run benchmarks: pnpm bench

🐳 Docker

Run the project in consistent, isolated environments with Docker.

Docker services

  • dev - development container with source mounts and hot editing support
  • test - runs npm test in an isolated container
  • lint - runs npm run lint in an isolated container
  • build - runs npm run build in an isolated container
  • prod - production image using the final build output

Common commands

docker compose run --rm dev
docker compose run --rm test
docker compose run --rm lint
docker compose run --rm build

docker build --target development -t ts-collections:dev .
docker build --target production -t ts-collections:prod .

Benefits

  • Consistent environment across machines and CI/CD
  • Strong isolation from local machine differences
  • Reproducible development and test workflows
  • Smaller, production-focused runtime images

Image targets

  • --target development for local development workflows
  • --target production for lean deployable images

📄 License

This project is licensed under the MIT License - see LICENSE for details.

🙏 Acknowledgments

🔗 Links


Made with ❤️ by the ts-collections team
⭐ Star us on GitHub if you find this useful!

About

ts-collections is a robust, Java-inspired collections framework for TypeScript, designed to provide developers with a powerful, type-safe, and feature-rich library for managing data structures. It is built with modern TypeScript features, ensuring high performance, scalability, and adherence to best practices.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors