Skip to content

Releases: telegramsjs/collection

2.0.0

14 Dec 21:05

Choose a tag to compare

@telegram.ts/collection@2.0.0

🎉 Major Release - Complete Rewrite

This is a major release of @telegram.ts/collection that brings it to feature parity with @discordjs/collection@2.1.1 while maintaining backward compatibility with your existing code. The library now extends Map directly and includes dozens of new utility methods for working with collections.

✨ New Features

Core Collection Methods

  • hasAll(...keys) - Check if all specified keys exist in the collection
  • hasAny(...keys) - Check if any of the specified keys exist in the collection
  • first(amount?) / firstKey(amount?) - Get the first value(s) or key(s) from the collection
  • last(amount?) / lastKey(amount?) - Get the last value(s) or key(s) from the collection
  • at(index) / keyAt(index) - Get value/key at a specific index (supports negative indices)
  • random(amount?) / randomKey(amount?) - Get random value(s) or key(s) from the collection

Array-like Methods

  • findLast(fn) - Find the last element that matches a condition
  • findLastKey(fn) - Find the last key where the value matches a condition
  • sweep(fn) - Remove items matching a condition and return the count of removed items
  • partition(fn) - Split collection into two collections based on a condition
  • flatMap(fn) - Map and flatten results into a single collection
  • mapValues(fn) - Map values while preserving keys
  • reduce(fn, initial?) - Reduce collection to a single value
  • reduceRight(fn, initial?) - Reduce collection from right to left
  • every(fn) - Check if all items pass a test
  • some(fn) - Check if any item passes a test

Utility Methods

  • each(fn) - Iterate over the collection (chainable)
  • tap(fn) - Run a function on the collection and return it (chainable)
  • clone() - Create a shallow copy of the collection
  • concat(...collections) - Merge multiple collections into a new one
  • equals(collection) - Deep equality check with another collection
  • toSorted(compareFn?) - Return a new sorted collection without modifying the original
  • toReversed() - Return a new reversed collection without modifying the original

Set Operations

  • intersect(other) - Get items present in both collections
  • difference(other) - Get items present in one collection but not the other
  • subtract(other) - Get items in this collection but not in the other
  • merge(other, whenInSelf, whenInOther, whenInBoth) - Advanced merging with custom logic

Array Methods

  • with(index, value) - Return a new collection with a value changed at an index
  • toSpliced(start, deleteCount?, ...items) - Return a new collection with items removed/added

Helper Methods

  • ensure(key, defaultGenerator) - Get a value or set it if it doesn't exist
  • toArray() - Get an array of values (cached for performance)
  • keyArray() - Get an array of keys (cached for performance)
  • toMap() - Convert collection to a native Map

🔄 Breaking Changes

Collection now extends Map

The Collection class now extends JavaScript's native Map class, giving you access to all standard Map methods while adding powerful utility methods on top.

Property Changes

  • Removed: items property - Collection now extends Map directly, use the collection itself instead of .items
    • Before: collection.items.get(key)
    • After: collection.get(key)

Method Signature Changes

  • keys() - Now returns an IterableIterator<K> (from Map) instead of K[]
    • To get an array: Use keyArray() or [...collection.keys()]
  • values() - Now returns an IterableIterator<V> (from Map) instead of V[]
    • To get an array: Use toArray() or [...collection.values()]
  • entries() - Now returns an IterableIterator<[K, V]> (from Map) instead of Entry<K, V>[]
    • To get an array: Use [...collection.entries()]

Renamed Methods

  • sweep() - Changed behavior: now removes duplicates → Use the new sweep(fn) with a filter function
    • Old behavior: collection.sweep() removed duplicates
    • New behavior: collection.sweep(fn) removes items matching the filter and returns count removed
    • To remove duplicates: Use a custom implementation or filter

Removed Methods

  • reverse() - The method now reverses in place; use toReversed() for a new collection
  • toSplised() - Renamed to toSpliced() to match JavaScript naming conventions

🚀 Improvements

Performance

  • Caching: toArray() and keyArray() now cache results for better performance
  • Native Map: Extending Map directly provides better performance and memory usage
  • Optimized iterations: Many methods now use more efficient iteration patterns

Type Safety

  • Better TypeScript support: Improved type inference for filter, partition, and other methods
  • Type guards: Methods like filter and every now support TypeScript type guards
  • ReadonlyCollection type: New type for read-only views of collections

Developer Experience

  • Method chaining: Many methods now return this for better chaining (each, tap, sort)
  • Consistent API: All methods follow JavaScript's Array/Map conventions
  • Better documentation: All methods now have comprehensive JSDoc comments with examples

📦 Migration Guide

Update your imports

// No changes needed - same import
import { Collection } from '@telegram.ts/collection';

Update direct property access

// Before
const map = collection.items;
map.forEach(...);

// After
collection.forEach(...);

Update array method calls

// Before
const keys = collection.keys();
const values = collection.values();

// After  
const keys = collection.keyArray(); // or [...collection.keys()]
const values = collection.toArray(); // or [...collection.values()]

Update sweep usage

// Before (remove duplicates)
collection.sweep();

// After (remove items matching condition)
collection.sweep((value, key) => shouldRemove(value));

// To remove duplicates, use filter
const uniqueCollection = collection.filter((value, key, coll) => {
  return coll.keyOf(value) === key;
});

💡 Examples

Working with first/last items

const collection = new Collection([
  ['a', 1],
  ['b', 2],
  ['c', 3],
]);

collection.first(); // 1
collection.first(2); // [1, 2]
collection.last(); // 3
collection.lastKey(); // 'c'

Partitioning data

const [premium, regular] = users.partition(user => user.isPremium);
console.log(`Premium users: ${premium.size}, Regular users: ${regular.size}`);

Chaining operations

collection
  .tap(c => console.log(`Starting with ${c.size} items`))
  .filter(item => item.active)
  .each(item => console.log(item.name))
  .sort((a, b) => a.priority - b.priority);

Set operations

const activeUsers = userCollection.filter(u => u.active);
const premiumUsers = userCollection.filter(u => u.premium);

// Users that are both active AND premium
const activePremium = activeUsers.intersect(premiumUsers);

// Users that are active OR premium (but not both)
const exclusiveUsers = activeUsers.difference(premiumUsers);

Ensuring values exist

// Get or create default value
const settings = guildSettings.ensure(guildId, () => ({
  prefix: '!',
  language: 'en',
}));

🙏 Credits

This release brings @telegram.ts/collection to feature parity with @discordjs/collection, maintaining the excellent API design while adapting it for telegram.ts use cases.