Immutable HashMap and HashSet implementations for TypeScript
npm install @rimbu/hashed

!License
!Types Included
!Node
!Bun
!ESM + CJS
@rimbu/hashedFast, immutable hash-based maps and sets for TypeScript & JavaScript.
@rimbu/hashed provides efficient, type-safe HashMap and HashSet implementations. These use configurable Hasher instances and Eq equality comparers under the hood, giving you predictable hashing and fast lookups for arbitrary keys and values – from primitives to complex objects and streams.
Use it whenever you need hash-based collections, custom hashing/equality, or want to build rich immutable models backed by persistent data structures.
---
1. Why @rimbu/hashed?
2. Feature Highlights
3. Quick Start
4. Core Concepts & Types
5. Configuring Hashers & Contexts
6. Installation
7. Ecosystem & Integration
8. Contributing
9. License
10. Attributions
---
@rimbu/hashed?Plain JavaScript Map / Set give you basic hash semantics, but you often need:
- Stable hashing for complex values – objects, arrays, tuples, dates, streams.
- Custom equality – case-insensitive strings, domain-specific identity, etc.
- Immutable semantics – structural sharing, safe reuse across your app.
@rimbu/hashed focuses on:
- Configurable hashing via Hasher utilities – choose how values are hashed.
- Pluggable equality via Eq – control when values are considered equal.
- Immutable collections – operations return new HashMap / HashSet instances.
- Context-based factories – HashMap.Context and HashSet.Context let you tune performance characteristics (block size, collision strategy).
If you outgrow the default Map / Set, or need consistent hashing across environments, @rimbu/hashed is a solid fit.
---
- HashMap & HashSet – immutable, type-invariant collections with O(1)-style lookups.
- Non-empty variants – HashMap.NonEmpty / HashSet.NonEmpty for stronger type guarantees.
- Builders – HashMap.Builder / HashSet.Builder for efficient bulk construction and mutation before freezing.
- Configurable contexts – use HashMap.createContext / HashSet.createContext to plug in custom Hasher, Eq, and block sizing.
- Rich hasher utilities – Hasher.numberHasher, Hasher.stringHasher, Hasher.anyDeepHasher, Hasher.objectHasher, and more in @rimbu/hashed/common.
- Stream integration – many APIs accept StreamSource inputs and expose Stream outputs for composable data flows.
---
``ts
import { HashMap, HashSet } from '@rimbu/hashed';
// HashSet: unique values
const users = HashSet.of('alice', 'bob', 'alice');
console.log(users.toString()); // HashSet('alice', 'bob')
// HashMap: key → value entries
const scores = HashMap.of([1, 'low'], [2, 'medium'], [3, 'high']);
console.log(scores.get(2)); // 'medium'
console.log(scores.hasKey(4)); // false
// Immutable updates
const updated = scores.set(2, 'mid');
console.log(updated.get(2)); // 'mid'
console.log(scores.get(2)); // 'medium' (original unchanged)
`
Try Rimbu (including @rimbu/hashed) live in the browser using the
Rimbu Sandbox on CodeSandbox.
---
From @rimbu/hashed:
| Name | Description |
| ------------------------ | ---------------------------------------------------------------------------------------------------- |
| HashMap | Immutable, type-invariant hash map from keys K to values V. |HashMap.NonEmpty
| | Non-empty refinement of HashMap with stronger type guarantees. |HashMap.Context
| | Factory/context for creating HashMap instances for keys up to type UK. |HashMap.Builder
| | Mutable builder for efficiently constructing or mutating a HashMap before freezing it. |HashSet
| | Immutable, type-invariant hash set of values T. |HashSet.NonEmpty
| | Non-empty refinement of HashSet. |HashSet.Context
| | Factory/context for creating HashSet instances for values up to type UT. |HashSet.Builder
| | Mutable builder for efficiently constructing or mutating a HashSet before freezing it. |Hasher
| | Interface describing a hasher for values up to type UK. |Hasher.*
| helpers | A family of hasher factories (e.g. numberHasher, stringHasher, anyFlatHasher, objectHasher). |
The package also re-exports the sub-packages:
- @rimbu/hashed/map – HashMap-specific interfaces and helpers.@rimbu/hashed/set
- – HashSet-specific interfaces and helpers.@rimbu/hashed/common
- – shared hasher utilities and low-level building blocks.
`ts
import { HashMap } from '@rimbu/hashed';
// Construction
const empty = HashMap.empty
const fromEntries = HashMap.of([1, 'one'], [2, 'two']);
// Size & emptiness
empty.isEmpty; // true
fromEntries.size; // 2
// Lookups
fromEntries.hasKey(1); // true
fromEntries.get(2); // 'two'
// Removing keys (returns new map)
const without = fromEntries.removeKey(1);
without.hasKey(1); // false
`
`ts
import { HashSet } from '@rimbu/hashed';
const s1 = HashSet.of('a', 'b', 'c', 'a');
s1.size; // 3
s1.has('b'); // true
const s2 = s1.add('d'); // new set
const s3 = s2.remove('a'); // new set
console.log(s1.toString()); // HashSet('a', 'b', 'c')
console.log(s3.toString()); // HashSet('b', 'c', 'd')
`
See the Map docs,
Set docs,
and the Hashed API reference
for the complete API surface.
---
One of the strengths of @rimbu/hashed is full control over how values are hashed.
`ts
import { Hasher } from '@rimbu/hashed/common';
const numHasher = Hasher.numberHasher();
const strHasher = Hasher.stringHasher();
const deepHasher = Hasher.anyDeepHasher();
numHasher.hash(42); // 32‑bit hash
strHasher.hash('Hello');
deepHasher.hash({ a: [1, 2, 3], b: { c: 5 } });
`
There are many helpers for common scenarios:
- Hasher.numberHasher() / Hasher.booleanHasher() / Hasher.bigintHasher()Hasher.stringHasher()
- / Hasher.stringCaseInsensitiveHasher()Hasher.arrayHasher()
- / Hasher.streamSourceHasher()Hasher.objectHasher()
- / Hasher.objectShallowHasher() / Hasher.objectDeepHasher()Hasher.anyFlatHasher()
- / Hasher.anyShallowHasher() / Hasher.anyDeepHasher()
`ts
import { HashMap } from '@rimbu/hashed';
import { Hasher } from '@rimbu/hashed/common';
// Case-insensitive string keys
const ctx = HashMap.createContext
hasher: Hasher.stringCaseInsensitiveHasher(),
});
const m = ctx.of(['Key', 1], ['OTHER', 2]);
m.hasKey('key'); // true
m.hasKey('other'); // true
`
`ts
import { HashSet } from '@rimbu/hashed';
import { Hasher } from '@rimbu/hashed/common';
// Deep structural hashing for objects
const ctx = HashSet.createContext<{ id: number; tags: string[] }>({
hasher: Hasher.anyDeepHasher(),
});
const set = ctx.of({ id: 1, tags: ['a', 'b'] }, { id: 2, tags: ['c'] });
set.has({ id: 1, tags: ['a', 'b'] }); // true (structurally equal)
`
For more on contexts, see the HashMap.Context and HashSet.Context sections in the
API reference.
---
`sh`
npm install @rimbu/hashedor
yarn add @rimbu/hashedor
bun add @rimbu/hashedor
deno add npm:@rimbu/hashed
Then:
`ts`
import { HashMap, HashSet } from '@rimbu/hashed/mod.ts';
@rimbu/hashed ships both ESM and CJS builds. Use it with any modern bundler
(Vite, Webpack, esbuild, Bun, etc.) or directly in Node ESM projects.
---
- Part of the broader Rimbu collection ecosystem – interoperates with @rimbu/bimap,@rimbu/ordered
, @rimbu/collection-types, and @rimbu/stream`.
- Ideal for modelling key/value stores, index structures, membership sets, caches, and more.
- Works seamlessly with other Rimbu collections and utilities for building rich, immutable data models.
Explore more at the Rimbu documentation and the
Hashed API docs.
---
We welcome contributions! See the
Contributing guide for details.
_Made with contributors-img._
---
MIT © Rimbu contributors. See LICENSE for details.
---
Created and maintained by Arvid Nicolaas. Logo © Rimbu.