Dict — dictionary utilities
You reach for a Map when you need to associate values with keys that aren’t strings, or when
you want insertion-order iteration guaranteed, or when you’re working with a large collection
where key membership checks matter. The native Map API gives you this, but it’s mutation-based
and doesn’t compose with pipe.
Dict wraps ReadonlyMap<K, V> with a set of pure, data-last functions that do.
Creating a dictionary
Section titled “Creating a dictionary”The three main constructors cover the common cases. Dict.empty() starts you with nothing.
Dict.fromEntries converts an array of key-value pairs — the same format you’d use with
Object.fromEntries, but for maps with any key type. Dict.fromRecord imports a plain object
when you already have one:
Dict.singleton is useful when you’re building up a map incrementally and want a typed
starting point with one known entry.
Looking up values safely
Section titled “Looking up values safely”The native Map.get returns V | undefined, which forces a null check at every call site.
Dict.lookup returns Maybe<V> instead — the absence of a key is explicit in the type:
When you only need a boolean, Dict.has is the right tool — it avoids allocating an Maybe
for what is essentially a membership test:
Transforming values
Section titled “Transforming values”Dict.map applies a function to every value, returning a new dictionary with the same keys.
Dict.mapWithKey is the same but also passes the key to the function:
Filtering
Section titled “Filtering”Dict.filter removes entries whose values don’t match a predicate. Dict.filterWithKey also
exposes the key to the predicate, which is useful when the decision depends on both:
Modifying individual entries
Section titled “Modifying individual entries”Dict.insert adds or replaces a single entry. Dict.remove removes one. Neither mutates the
original — both return a new dictionary:
For the common pattern of incrementing a counter or initialising a value on first access,
Dict.upsert provides a single operation. It calls your function with Some(currentValue) if
the key exists, or None if it doesn’t:
Combining dictionaries
Section titled “Combining dictionaries”Dict.union merges two dictionaries. When a key exists in both, the value from other takes
precedence — the same behaviour as spreading objects:
Dict.intersection keeps only the keys that appear in both dictionaries, taking values from
the left. Dict.difference removes from the left any keys that appear in the right:
Removing absent values with compact
Section titled “Removing absent values with compact”When you build a dictionary from fallible lookups — mapping over IDs that might not exist — you
end up with ReadonlyMap<K, Maybe<V>>. Dict.compact collapses that into ReadonlyMap<K, V>:
Folding and converting
Section titled “Folding and converting”Dict.reduce collapses the dictionary to a single value. Dict.toRecord converts a
string-keyed dictionary back to a plain object when you need to pass it to code that expects one:
Composing it all
Section titled “Composing it all”Dict operations chain naturally in pipe. Here, a dictionary of raw exam results is built,
filtered to passing grades, scaled, and summed:
When to use Dict
Section titled “When to use Dict”Use Dict when:
- You need keys that aren’t strings — numbers, objects, or any other type
- You need guaranteed insertion-order iteration over entries
- You’re building lookup tables that grow and shrink over time
- You want
lookupto returnMaybeinstead of a nullable value
Keep using Rec when:
- Your keys are always strings and you’re working with plain objects from JSON or APIs
- You need
pick,omit, ormapKeysoperations (not available onDict) - You’re interoperating with code that expects
Record<string, V>directly