Skip to main content

Class-based API for Immutable TypeScript Collections

This module is the main import of immutable-collections and implements the class-based API. This API consists of the HashMap, HashSet, OrderedMap, OrderedSet, and LazySeq classes (along with some utility functions).

import { HashMap } from "@seedtactics/immutable-collections";

const h = HashMap.from([ [1, "Hello"], [2, "World"] ]);
console.log(h.get(1)); // prints Hello
console.log(h.get(2)); // prints World

const h2 = h.set(1, "Goodbye");
console.log(h2.get(1)); // prints Goodbye
console.log(h.get(1)); // prints Hello
class HashMap<K extends HashKey, V>
#Source

Immutable Hash Map

The HashMap<K, V> class stores key-value pairs where the keys have type K and the values type V. Keys can be numbers, strings, booleans, dates, or custom objects which implement the HashableObj and ComparableObj interfaces. HashMap implements the typescript-builtin ReadonlyMap interface (which consists of the read-only methods of the JS builtin Map).

See full class details for HashMap

class HashSet<T extends HashKey>
#Source

Immutable Hash Set

The HashSet<T> class stores numbers, strings, booleans, dates, or custom objects which implement the HashableObj and ComparableObj interface. HashSet implements the typescript-builtin ReadonlySet interface (which consists of the read-only methods of the JS builtin Set).

See full class details for HashSet

class OrderedMap<K extends OrderedMapKey, V>
#Source

Immutable Ordered Map

The OrderedMap<K, V> class stores key-value pairs where the keys have type K and the values type V. Keys can be numbers, strings, booleans, dates, or custom objects which implement the ComparableObj interface. The entries are stored in a balanced binary tree, and various methods can iterate over the entries in either ascending or descending order of keys. OrderedMap implements the typescript-builtin ReadonlyMap interface (which consists of the read-only methods of the JS builtin Map).

See full class details for OrderedMap

class OrderedSet<T extends OrderedMapKey>
#Source

Immutable Ordered Set

The OrderedSet<T> class stores numbers, strings, booleans, dates, or custom objects which implement the ComparableObj interface. OrderedSet implements the typescript-builtin ReadonlySet interface (which consists of the read-only methods of the JS builtin Set).

See full class details for OrderedSet

class LazySeq<T>
#Source

A class-wrapper around iterables

The LazySeq<T> class stores an iterable of type T and provides a number of methods to transform the iterable. The general format for data manipulation is to start with some data in a data structure such as an array, object, HashMap, etc. Create a new LazySeq chain starting from the initial data, call various transformation methods to map, group, filter, aggregate the data, and finally terminate the chain by converting back to a data structure. Because most of the transformation methods are lazy, the new terminating data structure can be built directly from the transformed data in one pass.

See full class details for LazySeq

Comparison Utils

export type OrderedMapKey = string | number | boolean | Date | ComparableObj;
#Source

The possible types for a key in an OrderedMap

export type ComparableObj = {
compare(other: ComparableObj): number;
};
#Source

Interface allowing custom key objects in an OrderedMap

If you wish to use a custom object as a key in a HashMap or OrderedMap, you must implement the compare function. The compare function should return a negative number if this < other, return zero if this equals other, and return a positive number if this > other. A common technique is to use subtraction to compare numbers and String.localeCompare to compare srings. Comparing multiple properties can either use a sequence of if statements or use || to combine.

Example
class SomeKey {
public readonly a: number;
public readonly b: string;
constructor(a: number, b: string) {
this.a = a;
this.b = b;
}

compare(other: SomeKey): number {
return (this.a - other.a) || this.b.localeCompare(other.b);
}
}
function mkCompareByProperties<T>(
...getKeys: ReadonlyArray<ToComparable<T>>
): (a: T, b: T) => -1 | 0 | 1
#Source

Combine multiple comparable properties into a single comparison function

mkCompareByProperties will return a comparison function for the type T which compares multiple properties in order. Each property is specified by an extraction function which extracts the property from the type T. The comparison function will compare each property in order, returning as soon as a single property is not equal. Strings are compared using localeCompare.

This function can optionally be used to implement ComparableObj, but typically a direct implementation is shorter. mkCompareByProperties is instead used primarily by LazySeq.

Example
type Foo = {
readonly someNum: number;
readonly someStr: string;
}

const compareFoo: (a: Foo, b: Foo) => -1 | 0 | 1 = mkCompareByProperties(
f => f.someNum,
{ desc: f => f.someStr }
);

console.log(compareFoo(
{ someNum: 1, someStr: "Hello"},
{ someNum: 2, someStr: "Hello"}
)); // prints -1
console.log(compareFoo(
{ someNum: 42, someStr: "AAA"},
{ someNum: 42, someStr: "ZZZ"}
)); // prints 1 due to descending ordering of the strings
export type ToComparableBase<T> =
| ((t: T) => number | null)
| ((t: T) => string | null)
| ((t: T) => boolean | null)
| ((t: T) => Date | null)
| ((t: T) => ComparableObj | null);
#Source

A function which converts or extracts a comparable value

This is used primarily by LazySeq to extract comparable values from an object for grouping.

export type ToComparable<T> =
| { asc: ToComparableBase<T> }
| { desc: ToComparableBase<T> }
| ToComparableBase<T>;
#Source

A function which converts or extracts a comparable value and a direction

This is used primarily by LazySeq to extract comparable values from an object for grouping, while also allowing you to specify if the ordering should be in ascending or descending order. For example, see LazySeq.distinctAndSortBy.

Hash Utils

export type HashKey = string | number | boolean | Date | (HashableObj & ComparableObj);
#Source

The possible types for a key in a HashMap

export type HashableObj = {
hash(): number;
};
#Source

Interface allowing custom key objects in a HashMap

If you wish to use a custom object as a key in a HashMap, you must implement the hash function defined in the HashableObj type and the compare function defined in the ComparableObj type. The hash value must be a 32-bit integer. The hashValues function can help implementing the hash function.

Example
class SomeKey {
public readonly a: number;
public readonly b: string;
constructor(a: number, b: string) {
this.a = a;
this.b = b;
}

hash(): number {
return hashValues(this.a, this.b);
}

compare(other: SomeKey): number {
return (this.a - other.a) || this.b.localeCompare(other.b);
}
}
function hashValues(
...vals: ReadonlyArray<
string | number | boolean | Date | HashableObj | null | undefined
>
): number
#Source

Combine multiple hashable values into a single hash

Useful helper function to hash multiple values to a single hash. This uses the FNV-1 hash function, which is NOT secure. If you need a secure hash, use something like highwayhash and implement a custom HashableObj interface.

export type ToHashable<T> =
| ((t: T) => number | null)
| ((t: T) => string | null)
| ((t: T) => boolean | null)
| ((t: T) => Date | null)
| ((t: T) => (HashableObj & ComparableObj) | null);
#Source

A function which converts or extracts a hashable value

This is used primarily by LazySeq to extract hashable values from an object for grouping. For example, see LazySeq.groupBy.