TxHashMap
Transactional hash maps for storing and updating key-value pairs inside Effect transactions.
A TxHashMap stores an immutable HashMap in a TxRef, so map reads and
writes can commit atomically with other transactional operations. Use it for
shared registries, counters, indexes, and other maps that need safe
read-modify-write sequences alongside related transactional state.
Combinators
Removes all entries from the TxHashMap.
Details
This function mutates the original TxHashMap by clearing all key-value pairs. It does not return a new TxHashMap reference.
Signature
declare function clear<K, V>(self: TxHashMap<K, V>): Effect<void>Example
(Clearing all entries)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const sessionMap = yield* TxHashMap.make( ["session1", { userId: "alice", expires: "2024-01-01T12:00:00Z" }], ["session2", { userId: "bob", expires: "2024-01-01T13:00:00Z" }], ["session3", { userId: "charlie", expires: "2024-01-01T14:00:00Z" }] )
// Check initial state yield* TxHashMap.size(sessionMap) // => 3
// Clear all sessions (e.g., during maintenance) yield* TxHashMap.clear(sessionMap)
// Verify cleared yield* TxHashMap.size(sessionMap) // => 0 return yield* TxHashMap.isEmpty(sessionMap)})
await Effect.runPromise(program) // => trueRemoves all None values from a TxHashMap containing Option values.
Details
This function returns a new TxHashMap reference with only the Some values unwrapped. The original TxHashMap is not modified.
Signature
declare function compact<K, A>(self: TxHashMap<K, Option<A>>): Effect<TxHashMap<K, A>>Example
(Compacting optional values)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a map with optional user data const userData = yield* TxHashMap.make< string, Option.Option<{ age: number; email?: string }> >( ["alice", Option.some({ age: 30, email: "alice@example.com" })], ["bob", Option.none()], // incomplete data ["charlie", Option.some({ age: 25 })], ["diana", Option.none()], // missing data ["eve", Option.some({ age: 28, email: "eve@example.com" })] )
// Remove all None values and unwrap Some values const validUsers = yield* TxHashMap.compact(userData)
yield* TxHashMap.size(validUsers) // => 3
yield* TxHashMap.get(validUsers, "alice") // => Option.some({ age: 30, email: "alice@example.com" }) yield* TxHashMap.get(validUsers, "bob") // => Option.none()
// Useful for cleaning up optional data processing results const userAges = yield* TxHashMap.map(validUsers, (user) => user.age) return (yield* TxHashMap.entries(userAges)).toSorted(([left], [right]) => left.localeCompare(right))})
await Effect.runPromise(program) // => [["alice", 30], ["charlie", 25], ["eve", 28]]Returns an array of all key-value pairs in the TxHashMap.
Signature
declare function entries<K, V>(self: TxHashMap<K, V>): Effect<Array<readonly [K, V]>>Example
(Reading entries)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const config = yield* TxHashMap.make( ["host", "localhost"], ["port", "3000"], ["ssl", "false"] )
return (yield* TxHashMap.entries(config)).toSorted(([left], [right]) => left.localeCompare(right))})
await Effect.runPromise(program) // => [["host", "localhost"], ["port", "3000"], ["ssl", "false"]]Filters the TxHashMap to keep only entries that satisfy the provided predicate.
Details
This function returns a new TxHashMap reference containing only the entries that match the condition. The original TxHashMap is not modified.
Signature
declare const filter: { <K, V, B>(predicate: (value: V, key: K) => value is B): (self: TxHashMap<K, V>) => Effect<TxHashMap<K, B>>; <K, V>(predicate: (value: V, key: K) => boolean): (self: TxHashMap<K, V>) => Effect<TxHashMap<K, V>>; <K, V, B>(self: TxHashMap<K, V>, predicate: (value: V, key: K) => value is B): Effect<TxHashMap<K, B>>; <K, V>(self: TxHashMap<K, V>, predicate: (value: V, key: K) => boolean): Effect<TxHashMap<K, V>>;}Example
(Filtering entries)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a product inventory const inventory = yield* TxHashMap.make( ["laptop", { price: 999, stock: 5, category: "electronics" }], ["mouse", { price: 29, stock: 50, category: "electronics" }], ["book", { price: 15, stock: 100, category: "books" }], ["phone", { price: 699, stock: 0, category: "electronics" }] )
// Filter to get only electronics in stock const electronicsInStock = yield* TxHashMap.filter( inventory, (product) => product.category === "electronics" && product.stock > 0 )
yield* TxHashMap.size(electronicsInStock) // => 2
// Data-last usage with pipe const expensiveItems = yield* inventory.pipe( TxHashMap.filter((product) => product.price > 500) )
yield* TxHashMap.size(expensiveItems) // => 2
// Type guard usage return yield* TxHashMap.filter( inventory, (product): product is typeof product & { price: number } => product.price > 50 )})
await Effect.runPromise(program)Combines filtering and mapping in a single operation. Applies a filter to each entry, keeping only successful results and transforming them.
Details
This function returns a new TxHashMap reference containing only the transformed entries that succeeded. The original TxHashMap is not modified.
Signature
declare const filterMap: { <V, K, A, X>(f: (input: V, key: K) => Result<A, X>): (self: TxHashMap<K, V>) => Effect<TxHashMap<K, A>>; <K, V, A, X>(self: TxHashMap<K, V>, f: (input: V, key: K) => Result<A, X>): Effect<TxHashMap<K, A>>;}Example
(Filtering and mapping entries)
import { Effect, Option, Result, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a mixed data map const userData = yield* TxHashMap.make( ["alice", { age: "30", role: "admin", active: true }], ["bob", { age: "invalid", role: "user", active: true }], ["charlie", { age: "25", role: "admin", active: false }], ["diana", { age: "28", role: "user", active: true }] )
// Extract valid ages for active admin users only const activeAdminAges = yield* TxHashMap.filterMap( userData, (user, username) => { if (!user.active || user.role !== "admin") return Result.failVoid const age = parseInt(user.age) if (isNaN(age)) return Result.failVoid return Result.succeed({ username, age, seniority: age > 27 ? "senior" : "junior" }) } )
const aliceData = yield* TxHashMap.get(activeAdminAges, "alice") aliceData // => Option.some({ username: "alice", age: 30, seniority: "senior" }) yield* TxHashMap.get(activeAdminAges, "charlie") // => Option.none()
// Data-last usage with pipe const validAges = yield* userData.pipe( TxHashMap.filterMap((user) => { const age = parseInt(user.age) return isNaN(age) ? Result.failVoid : Result.succeed(age) }) )
return yield* TxHashMap.size(validAges)})
await Effect.runPromise(program) // => 3Finds the first entry in the TxHashMap that matches the given predicate. Returns the key-value pair as a tuple wrapped in an Option.
Signature
declare const findFirst: { <K, V>(predicate: (value: V, key: K) => boolean): (self: TxHashMap<K, V>) => Effect<Option<[K, V]>>; <K, V>(self: TxHashMap<K, V>, predicate: (value: V, key: K) => boolean): Effect<Option<[K, V]>>;}Example
(Finding the first matching entry)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a task priority map const tasks = yield* TxHashMap.make( ["task1", { priority: 1, assignee: "alice", completed: false }], ["task2", { priority: 3, assignee: "bob", completed: true }], ["task3", { priority: 2, assignee: "alice", completed: false }] )
// Find first high-priority incomplete task const highPriorityTask = yield* TxHashMap.findFirst( tasks, (task) => task.priority >= 2 && !task.completed )
highPriorityTask // => Option.some(["task3", { priority: 2, assignee: "alice", completed: false }])
// Find first task assigned to specific user return yield* tasks.pipe( TxHashMap.findFirst((task) => task.assignee === "alice") )})
await Effect.runPromise(program) // => Option.some(["task1", { priority: 1, assignee: "alice", completed: false }])Maps each entry effectfully to a TxHashMap and flattens the produced maps.
Details
This function returns a new TxHashMap reference with the flattened results. The original TxHashMap is not modified.
Signature
declare const flatMap: { <A, V, K>(f: (value: V, key: K) => Effect<TxHashMap<K, A>>): (self: TxHashMap<K, V>) => Effect<TxHashMap<K, A>>; <K, V, A>(self: TxHashMap<K, V>, f: (value: V, key: K) => Effect<TxHashMap<K, A>>): Effect<TxHashMap<K, A>>;}Example
(Flat mapping entries)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a department-employee map const departments = yield* TxHashMap.make( ["engineering", ["alice", "bob"]], ["marketing", ["charlie", "diana"]] )
// Expand each department into individual employee entries with metadata const employeeDetails = yield* TxHashMap.flatMap( departments, (employees, department) => Effect.gen(function*() { const employeeMap = yield* TxHashMap.empty< string, { department: string; role: string } >() for (let i = 0; i < employees.length; i++) { const employee = employees[i] const role = i === 0 ? "lead" : "member" yield* TxHashMap.set(employeeMap, employee, { department, role }) } return employeeMap }) )
// Check the flattened result yield* TxHashMap.get(employeeDetails, "alice") // => Option.some({ department: "engineering", role: "lead" }) yield* TxHashMap.get(employeeDetails, "charlie") // => Option.some({ department: "marketing", role: "lead" }) return yield* TxHashMap.size(employeeDetails)})
await Effect.runPromise(program) // => 4Executes a side-effect function for each entry in the TxHashMap. The function receives the value and key as parameters and can perform effects.
Signature
declare const forEach: { <V, K, R, E>(f: (value: V, key: K) => Effect<void, E, R>): (self: TxHashMap<K, V>) => Effect<void, E, R>; <K, V, R, E>(self: TxHashMap<K, V>, f: (value: V, key: K) => Effect<void, E, R>): Effect<void, E, R>;}Example
(Running effects for each entry)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a log processing map const logs = yield* TxHashMap.make( ["error.log", { size: 1024, level: "error" }], ["access.log", { size: 2048, level: "info" }], ["debug.log", { size: 512, level: "debug" }] )
const messages: Array<string> = [] yield* TxHashMap.forEach(logs, (logInfo, filename) => Effect.sync(() => { messages.push(`${filename}: ${logInfo.size} bytes (${logInfo.level})`) }))
return messages.sort()})
const result = await Effect.runPromise(program)result // => ["access.log: 2048 bytes (info)", "debug.log: 512 bytes (debug)", "error.log: 1024 bytes (error)"]Looks up the value for the specified key in the TxHashMap.
Signature
declare const get: { <K1, K>(key: K1): <V>(self: TxHashMap<K, V>) => Effect<Option<V>>; <K1, K, V>(self: TxHashMap<K, V>, key: K1): Effect<Option<V>>;}Example
(Looking up values safely)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { const userMap = yield* TxHashMap.make( ["alice", { name: "Alice", role: "admin" }], ["bob", { name: "Bob", role: "user" }] )
// Safe lookup - returns Option yield* TxHashMap.get(userMap, "alice") // => Option.some({ name: "Alice", role: "admin" }) yield* TxHashMap.get(userMap, "charlie") // => Option.none()
// Use with pipe syntax for type-safe access return yield* TxHashMap.get(userMap, "bob")})
await Effect.runPromise(program) // => Option.some({ name: "Bob", role: "user" })Looks up the value for the specified key using a caller-supplied hash.
Gotchas
The supplied hash must be the hash for the same key, such as a precomputed
Hash.hash(key) value. If the hash does not match the key, an existing entry
may not be found.
Signature
declare const getHash: { <K1, K>(key: K1, hash: number): <V>(self: TxHashMap<K, V>) => Effect<Option<V>>; <K1, K, V>(self: TxHashMap<K, V>, key: K1, hash: number): Effect<Option<V>>;}Example
(Looking up values with precomputed hashes)
import { Effect, Hash, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a cache with user sessions const cache = yield* TxHashMap.make( ["session_abc123", { userId: "user1", lastActive: 1_700_000_000_000 }], ["session_def456", { userId: "user2", lastActive: 1_700_000_060_000 }] )
// When you have precomputed hash (e.g., from another lookup) const sessionId = "session_abc123" const precomputedHash = Hash.string(sessionId)
// Use hash-optimized lookup for performance in hot paths const session = yield* TxHashMap.getHash(cache, sessionId, precomputedHash) session // => Option.some({ userId: "user1", lastActive: 1_700_000_000_000 })
// This avoids recomputing the hash when you already have it return yield* TxHashMap.getHash( cache, "invalid", Hash.string("invalid") )})
await Effect.runPromise(program) // => Option.none()Returns an array of all keys in the TxHashMap.
Signature
declare function keys<K, V>(self: TxHashMap<K, V>): Effect<Array<K>>Example
(Reading keys)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { const userRoles = yield* TxHashMap.make( ["alice", "admin"], ["bob", "user"], ["charlie", "moderator"] )
const usernames = (yield* TxHashMap.keys(userRoles)).sort() usernames // => ["alice", "bob", "charlie"]
// Useful for iteration const assignments: Array<string> = [] for (const username of usernames) { const role = yield* TxHashMap.get(userRoles, username) if (role._tag === "Some") { assignments.push(`${username}: ${role.value}`) } } return assignments})
await Effect.runPromise(program) // => ["alice: admin", "bob: user", "charlie: moderator"]Transforms all values in the TxHashMap using the provided function, preserving keys.
Details
This function returns a new TxHashMap reference with the transformed values. The original TxHashMap is not modified.
Signature
declare const map: { <A, V, K>(f: (value: V, key: K) => A): (self: TxHashMap<K, V>) => Effect<TxHashMap<K, A>>; <K, V, A>(self: TxHashMap<K, V>, f: (value: V, key: K) => A): Effect<TxHashMap<K, A>>;}Example
(Mapping values)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a user profile map const profiles = yield* TxHashMap.make( ["alice", { name: "Alice", age: 30, active: true }], ["bob", { name: "Bob", age: 25, active: false }], ["charlie", { name: "Charlie", age: 35, active: true }] )
// Transform to extract just names with greeting const greetings = yield* TxHashMap.map( profiles, (profile, userId) => `Hello, ${profile.name}! (User: ${userId})` )
// Check the transformed values yield* TxHashMap.get(greetings, "alice") // => Option.some("Hello, Alice! (User: alice)")
// Data-last usage with pipe const ages = yield* profiles.pipe( TxHashMap.map((profile) => profile.age) )
yield* TxHashMap.get(ages, "alice") // => Option.some(30)
// Original map is unchanged return yield* TxHashMap.get(profiles, "alice")})
await Effect.runPromise(program) // => Option.some({ name: "Alice", age: 30, active: true })Updates the value for the specified key if it exists, returning the previous value in Some; returns None and leaves the map unchanged when the key is absent.
Details
This function mutates the original TxHashMap by updating the value at the specified key. It does not return a new TxHashMap reference.
Signature
declare const modify: { <K, V>(key: K, f: (value: V) => V): (self: TxHashMap<K, V>) => Effect<Option<V>>; <K, V>(self: TxHashMap<K, V>, key: K, f: (value: V) => V): Effect<Option<V>>;}Example
(Updating existing values)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { const counters = yield* TxHashMap.make( ["downloads", 100], ["views", 250] )
// Increment existing counter const oldDownloads = yield* TxHashMap.modify( counters, "downloads", (count) => count + 1 ) oldDownloads // => Option.some(100)
yield* TxHashMap.get(counters, "downloads") // => Option.some(101)
// Try to modify non-existent key const nonExistent = yield* TxHashMap.modify( counters, "clicks", (count) => count + 1 ) nonExistent // => Option.none()
// Update views counter with direct method call yield* TxHashMap.modify(counters, "views", (views) => views * 2) return yield* TxHashMap.get(counters, "views")})
await Effect.runPromise(program) // => Option.some(500)Updates the value for the specified key using an Option-based update function.
Details
This function mutates the original TxHashMap by updating, adding, or removing the key-value pair based on the function result. It does not return a new TxHashMap reference.
Signature
declare const modifyAt: { <K, V>(key: K, f: (value: Option<V>) => Option<V>): (self: TxHashMap<K, V>) => Effect<void>; <K, V>(self: TxHashMap<K, V>, key: K, f: (value: Option<V>) => Option<V>): Effect<void>;}Example
(Updating values with Option)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { const storage = yield* TxHashMap.make<string, string | number>([ "file1.txt", "content1" ], ["access_count", 0]) const increment = Option.map((value: string | number) => typeof value === "number" ? value + 1 : value)
// Increment existing counter yield* TxHashMap.modifyAt(storage, "access_count", increment) yield* TxHashMap.get(storage, "access_count") // => Option.some(1)
// Increment existing counter again yield* TxHashMap.modifyAt(storage, "access_count", increment) yield* TxHashMap.get(storage, "access_count") // => Option.some(2)
// Update an existing string entry yield* TxHashMap.modifyAt( storage, "file1.txt", Option.map((value) => typeof value === "string" ? `${value}.bak` : value) ) return yield* TxHashMap.get(storage, "file1.txt")})
await Effect.runPromise(program) // => Option.some("content1.bak")Reduces the TxHashMap entries to a single value by applying a reducer function. Iterates over all key-value pairs and accumulates them into a final result.
Signature
declare const reduce: { <A, V, K>(zero: A, f: (accumulator: A, value: V, key: K) => A): (self: TxHashMap<K, V>) => Effect<A>; <K, V, A>(self: TxHashMap<K, V>, zero: A, f: (accumulator: A, value: V, key: K) => A): Effect<A>;}Example
(Reducing entries)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a sales data map const sales = yield* TxHashMap.make( ["Q1", 15000], ["Q2", 18000], ["Q3", 22000], ["Q4", 25000] )
// Calculate total sales const totalSales = yield* TxHashMap.reduce( sales, 0, (total, amount) => total + amount ) totalSales // => 80000
// Data-last usage with pipe const quarterlyReport = yield* sales.pipe( TxHashMap.reduce( { quarters: 0, total: 0, max: 0 }, (report, amount, quarter) => ({ quarters: report.quarters + 1, total: report.total + amount, max: Math.max(report.max, amount) }) ) ) return quarterlyReport})
await Effect.runPromise(program) // => { quarters: 4, total: 80000, max: 25000 }Removes the specified key from the TxHashMap.
Details
This function mutates the original TxHashMap by removing the specified key-value pair. It does not return a new TxHashMap reference.
Signature
declare const remove: { <K1, K>(key: K1): <V>(self: TxHashMap<K, V>) => Effect<boolean>; <K1, K, V>(self: TxHashMap<K, V>, key: K1): Effect<boolean>;}Example
(Removing keys)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const cache = yield* TxHashMap.make( ["user:1", { name: "Alice", lastSeen: "2024-01-01" }], ["user:2", { name: "Bob", lastSeen: "2024-01-02" }], ["user:3", { name: "Charlie", lastSeen: "2023-12-30" }] )
// Remove expired user yield* TxHashMap.remove(cache, "user:3") // => true
// Try to remove non-existent key yield* TxHashMap.remove(cache, "user:999") // => false
// Verify removal yield* TxHashMap.has(cache, "user:3") // => false return yield* TxHashMap.size(cache)})
await Effect.runPromise(program) // => 2removeMany
Removes multiple keys from the TxHashMap.
Details
This function mutates the original TxHashMap by removing all specified keys. It does not return a new TxHashMap reference.
Signature
declare const removeMany: { <K1, K>(keys: Iterable<K1>): <V>(self: TxHashMap<K, V>) => Effect<void>; <K1, K, V>(self: TxHashMap<K, V>, keys: Iterable<K1>): Effect<void>;}Example
(Removing multiple keys)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a cache with temporary data const cache = yield* TxHashMap.make( ["session_1", { user: "alice", expires: "2024-01-01" }], ["session_2", { user: "bob", expires: "2024-01-01" }], ["session_3", { user: "charlie", expires: "2024-12-31" }], ["temp_data_1", { value: "temporary" }], ["temp_data_2", { value: "also_temporary" }] )
yield* TxHashMap.size(cache) // => 5
// Remove expired sessions and temporary data const keysToRemove = ["session_1", "session_2", "temp_data_1", "temp_data_2"] yield* TxHashMap.removeMany(cache, keysToRemove)
yield* TxHashMap.size(cache) // => 1
// Verify only the valid session remains yield* TxHashMap.get(cache, "session_3") // => Option.some({ user: "charlie", expires: "2024-12-31" })
// Can also remove from Set, Array, or any iterable const moreKeysToRemove = new Set(["session_3"]) yield* TxHashMap.removeMany(cache, moreKeysToRemove) return yield* TxHashMap.isEmpty(cache)})
await Effect.runPromise(program) // => trueSets the value for the specified key in the TxHashMap.
Details
This function mutates the original TxHashMap by updating its internal state. It does not return a new TxHashMap reference.
Signature
declare const set: { <K, V>(key: K, value: V): (self: TxHashMap<K, V>) => Effect<void>; <K, V>(self: TxHashMap<K, V>, key: K, value: V): Effect<void>;}Example
(Setting values)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { const inventory = yield* TxHashMap.make( ["laptop", 5], ["mouse", 20] )
// Update existing item yield* TxHashMap.set(inventory, "laptop", 3) yield* TxHashMap.get(inventory, "laptop") // => Option.some(3)
// Add new item yield* TxHashMap.set(inventory, "keyboard", 15) yield* TxHashMap.get(inventory, "keyboard") // => Option.some(15)
// Use with pipe syntax yield* TxHashMap.set("tablet", 8)(inventory) return yield* TxHashMap.get(inventory, "tablet")})
await Effect.runPromise(program) // => Option.some(8)Sets multiple key-value pairs in the TxHashMap.
Details
This function mutates the original TxHashMap by setting all provided key-value pairs. It does not return a new TxHashMap reference.
Signature
declare const setMany: { <K1, K, V1, V>(entries: Iterable<readonly [K1, V1]>): (self: TxHashMap<K, V>) => Effect<void>; <K1, K, V1, V>(self: TxHashMap<K, V>, entries: Iterable<readonly [K1, V1]>): Effect<void>;}Example
(Setting multiple entries)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create an empty product catalog const catalog = yield* TxHashMap.empty< string, { price: number; stock: number } >()
// Bulk load initial products const initialProducts: Array< readonly [string, { price: number; stock: number }] > = [ ["laptop", { price: 999, stock: 5 }], ["mouse", { price: 29, stock: 50 }], ["keyboard", { price: 79, stock: 20 }], ["monitor", { price: 299, stock: 8 }] ]
yield* TxHashMap.setMany(catalog, initialProducts)
yield* TxHashMap.size(catalog) // => 4
// Update prices with a new batch const priceUpdates: Array< readonly [string, { price: number; stock: number }] > = [ ["laptop", { price: 899, stock: 5 }], // sale price ["mouse", { price: 25, stock: 50 }], // sale price ["webcam", { price: 89, stock: 12 }] // new product ]
yield* TxHashMap.setMany(catalog, priceUpdates)
yield* TxHashMap.size(catalog) // => 5
// Verify the updates yield* TxHashMap.get(catalog, "laptop") // => Option.some({ price: 899, stock: 5 })
// Can also use Map, Set of tuples, or any iterable of entries const jsMap = new Map([["tablet", { price: 399, stock: 3 }]]) yield* TxHashMap.setMany(catalog, jsMap) return yield* TxHashMap.get(catalog, "tablet")})
await Effect.runPromise(program) // => Option.some({ price: 399, stock: 3 })Returns the number of entries in the TxHashMap.
Signature
declare function size<K, V>(self: TxHashMap<K, V>): Effect<number>Example
(Counting entries)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const metrics = yield* TxHashMap.make( ["requests", 1000], ["errors", 5], ["users", 50] )
yield* TxHashMap.size(metrics) // => 3
// Add more metrics yield* TxHashMap.set(metrics, "response_time", 250) yield* TxHashMap.size(metrics) // => 4
// Remove a metric yield* TxHashMap.remove(metrics, "errors") return yield* TxHashMap.size(metrics)})
await Effect.runPromise(program) // => 3Returns an immutable snapshot of the current TxHashMap state.
Signature
declare function snapshot<K, V>(self: TxHashMap<K, V>): Effect<HashMap<K, V>>Example
(Taking immutable snapshots)
import { Effect, HashMap, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { const liveData = yield* TxHashMap.make( ["temperature", 22.5], ["humidity", 45.2], ["pressure", 1013.25] )
// Take snapshot for reporting const snapshot = yield* TxHashMap.snapshot(liveData)
// Continue modifying live data yield* TxHashMap.set(liveData, "temperature", 23.1) yield* TxHashMap.set(liveData, "wind_speed", 5.3)
// Snapshot remains unchanged HashMap.size(snapshot) // => 3 HashMap.get(snapshot, "temperature") // => Option.some(22.5)
// Can use regular HashMap operations on snapshot return HashMap.get(snapshot, "humidity")})
await Effect.runPromise(program) // => Option.some(45.2)Merges another HashMap into this TxHashMap. If both maps contain the same key, the value from the other map will be used.
Details
This function mutates the original TxHashMap by merging the provided HashMap into it. It does not return a new TxHashMap reference.
Signature
declare const union: { <K1, K, V1, V>(other: HashMap<K1, V1>): (self: TxHashMap<K, V>) => Effect<void>; <K1, K, V1, V>(self: TxHashMap<K, V>, other: HashMap<K1, V1>): Effect<void>;}Example
(Merging HashMaps)
import { Effect, HashMap, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create initial user preferences const userPrefs = yield* TxHashMap.make( ["theme", "light"], ["language", "en"], ["notifications", "enabled"] )
// New preferences to merge in const newSettings = HashMap.make( ["theme", "dark"], // will override existing ["timezone", "UTC"], // new setting ["sound", "enabled"] // new setting )
// Merge the new settings yield* TxHashMap.union(userPrefs, newSettings)
// Check the merged result yield* TxHashMap.get(userPrefs, "theme") // => Option.some("dark") yield* TxHashMap.get(userPrefs, "language") // => Option.some("en") yield* TxHashMap.get(userPrefs, "timezone") // => Option.some("UTC") return yield* TxHashMap.size(userPrefs)})
await Effect.runPromise(program) // => 5Returns an array of all values in the TxHashMap.
Signature
declare function values<K, V>(self: TxHashMap<K, V>): Effect<Array<V>>Example
(Reading values)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const scores = yield* TxHashMap.make( ["alice", 95], ["bob", 87], ["charlie", 92] )
const allScores = (yield* TxHashMap.values(scores)).sort((a, b) => a - b) allScores // => [87, 92, 95]
// Calculate average const average = allScores.reduce((sum, score) => sum + score, 0) / allScores.length average.toFixed(2) // => "91.33"
// Find maximum return Math.max(...allScores)})
await Effect.runPromise(program) // => 95Constructors
Creates an empty TxHashMap.
Signature
declare function empty<K, V>(): Effect<TxHashMap<K, V>>Example
(Creating an empty map)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create an empty transactional hash map const emptyMap = yield* TxHashMap.empty<string, number>()
// Verify it's empty yield* TxHashMap.isEmpty(emptyMap) // => true yield* TxHashMap.size(emptyMap) // => 0
// Start adding elements yield* TxHashMap.set(emptyMap, "first", 1) return yield* TxHashMap.size(emptyMap)})
await Effect.runPromise(program) // => 1fromIterable
Creates a TxHashMap from an iterable of key-value pairs.
Signature
declare function fromIterable<K, V>(entries: Iterable<readonly [K, V]>): Effect<TxHashMap<K, V>>Example
(Creating a map from an iterable)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create from various iterable sources const configEntries = [ ["database.host", "localhost"], ["database.port", "5432"], ["cache.enabled", "true"], ["logging.level", "info"] ] as const
const configMap = yield* TxHashMap.fromIterable(configEntries)
// Verify the configuration was loaded yield* TxHashMap.size(configMap) // => 4 yield* TxHashMap.get(configMap, "database.host") // => Option.some("localhost")
// Can also create from Map, Set of tuples, etc. const jsMap = new Map([["key1", "value1"], ["key2", "value2"]]) return yield* TxHashMap.fromIterable(jsMap)})
await Effect.runPromise(program)Creates a TxHashMap from the provided key-value pairs.
Signature
declare function make<K, V>(...entries: Array<readonly [K, V]>): Effect<TxHashMap<K, V>>Example
(Creating a map from entries)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a user directory const userMap = yield* TxHashMap.make( ["alice", { name: "Alice Smith", role: "admin" }], ["bob", { name: "Bob Johnson", role: "user" }], ["charlie", { name: "Charlie Brown", role: "user" }] )
// Check the initial size yield* TxHashMap.size(userMap) // => 3
// Access users yield* TxHashMap.get(userMap, "alice") // => Option.some({ name: "Alice Smith", role: "admin" }) return yield* TxHashMap.get(userMap, "david")})
await Effect.runPromise(program) // => Option.none()Getters
Returns an array of all key-value pairs in the TxHashMap.
This is an alias for the entries function, providing API consistency with HashMap.
Signature
declare function toEntries<K, V>(self: TxHashMap<K, V>): Effect<Array<readonly [K, V]>>Example
(Converting to entries)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const settings = yield* TxHashMap.make( ["theme", "dark"], ["language", "en-US"], ["timezone", "UTC"] )
// Get all entries as an array const sortedEntries = (yield* TxHashMap.toEntries(settings)) .toSorted(([left], [right]) => left.localeCompare(right)) sortedEntries // => [["language", "en-US"], ["theme", "dark"], ["timezone", "UTC"]]
// Convert to an object return Object.fromEntries(sortedEntries)})
await Effect.runPromise(program) // => { language: "en-US", theme: "dark", timezone: "UTC" }Returns an array of all values in the TxHashMap.
This is an alias for the values function, providing API consistency with HashMap.
Signature
declare function toValues<K, V>(self: TxHashMap<K, V>): Effect<Array<V>>Example
(Converting to values)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const inventory = yield* TxHashMap.make( ["laptop", { price: 999, stock: 5 }], ["mouse", { price: 29, stock: 50 }], ["keyboard", { price: 79, stock: 20 }] )
// Get all product information const products = yield* TxHashMap.toValues(inventory) products.length // => 3
// Calculate total inventory value const totalValue = products.reduce( (sum, product) => sum + (product.price * product.stock), 0 ) totalValue // => 8025
// Find products with low stock return products.filter((product) => product.stock < 10).length})
await Effect.runPromise(program) // => 1Guards
isTxHashMap
Returns true if the specified value is a TxHashMap, false otherwise.
Signature
declare function isTxHashMap<K, V>(value: unknown): value is TxHashMap<K, V>Example
(Checking TxHashMap values)
import { Effect, Exit, TxHashMap } from "effect"
const program = Effect.gen(function*() { const txMap = yield* TxHashMap.make(["key", "value"])
TxHashMap.isTxHashMap(txMap) // => true TxHashMap.isTxHashMap({}) // => false TxHashMap.isTxHashMap(null) // => false TxHashMap.isTxHashMap("not a map") // => false
// Useful for type guards in runtime checks const validateInput = (value: unknown) => { if (TxHashMap.isTxHashMap(value)) { // TypeScript now knows this is a TxHashMap return Effect.succeed("Valid TxHashMap") } return Effect.fail("Invalid input") }
yield* Effect.exit(validateInput(null)) // => Exit.fail("Invalid input") return yield* Effect.exit(validateInput(txMap))})
await Effect.runPromise(program) // => Exit.succeed("Valid TxHashMap")Models
A TxHashMap is a transactional hash map data structure that provides atomic operations on key-value pairs within Effect transactions. It uses an immutable HashMap internally with TxRef for transactional semantics, ensuring all operations are performed atomically.
Signature
interface TxHashMap<in out K, in out V> extends Inspectable, Pipeable { readonly "~effect/transactions/TxHashMap": "~effect/transactions/TxHashMap"; readonly ref: TxRef<HashMap<K, V>>;}Example
(Using transactional hash maps)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a transactional hash map const txMap = yield* TxHashMap.make(["user1", "Alice"], ["user2", "Bob"])
// Single operations are automatically transactional yield* TxHashMap.set(txMap, "user3", "Charlie") yield* TxHashMap.get(txMap, "user1") // => Option.some("Alice")
// Multi-step atomic operations yield* Effect.tx( Effect.gen(function*() { const currentUser = yield* TxHashMap.get(txMap, "user1") if (currentUser._tag === "Some") { yield* TxHashMap.set(txMap, "user1", currentUser.value + "_updated") yield* TxHashMap.remove(txMap, "user2") } }) )
return yield* TxHashMap.size(txMap)})
await Effect.runPromise(program) // => 2Other
The TxHashMap namespace contains type-level utilities and helper types for working with TxHashMap instances.
Example
(Reusing extracted TxHashMap types)
import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a transactional inventory map const inventory = yield* TxHashMap.make( ["laptop", { stock: 5, price: 999 }], ["mouse", { stock: 20, price: 29 }] )
// Extract types for reuse type ProductId = TxHashMap.TxHashMap.Key<typeof inventory> // string type Product = TxHashMap.TxHashMap.Value<typeof inventory> // { stock: number, price: number } type InventoryEntry = TxHashMap.TxHashMap.Entry<typeof inventory> // [string, Product]
// Use extracted types in functions const updateStock = (id: ProductId, newStock: number) => TxHashMap.modify( inventory, id, (product) => ({ ...product, stock: newStock }) )
yield* updateStock("laptop", 3) return yield* TxHashMap.get(inventory, "laptop")})
await Effect.runPromise(program) // => Option.some({ stock: 3, price: 999 })Predicates
Checks whether all entries in the TxHashMap satisfy the given predicate.
Signature
declare const every: { <K, V>(predicate: (value: V, key: K) => boolean): (self: TxHashMap<K, V>) => Effect<boolean>; <K, V>(self: TxHashMap<K, V>, predicate: (value: V, key: K) => boolean): Effect<boolean>;}Example
(Checking whether every entry matches)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a user permissions map const permissions = yield* TxHashMap.make( ["alice", { canRead: true, canWrite: true, canDelete: false }], ["bob", { canRead: true, canWrite: false, canDelete: false }], ["charlie", { canRead: true, canWrite: true, canDelete: true }] )
// Check if all users can read yield* TxHashMap.every( permissions, (perms) => perms.canRead ) // => true
// Check if all users can write yield* TxHashMap.every( permissions, (perms) => perms.canWrite ) // => false
// Data-last usage with pipe return yield* permissions.pipe( TxHashMap.every((perms, username) => perms.canRead && username.length > 2) )})
await Effect.runPromise(program) // => trueChecks whether the specified key exists in the TxHashMap.
Signature
declare const has: { <K1, K>(key: K1): <V>(self: TxHashMap<K, V>) => Effect<boolean>; <K1, K, V>(self: TxHashMap<K, V>, key: K1): Effect<boolean>;}Example
(Checking for keys)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const permissions = yield* TxHashMap.make( ["alice", ["read", "write"]], ["bob", ["read"]], ["charlie", ["admin"]] )
// Check if users exist yield* TxHashMap.has(permissions, "alice") // => true yield* TxHashMap.has(permissions, "david") // => false
// Use direct method call for type-safe access return yield* TxHashMap.has(permissions, "bob")})
await Effect.runPromise(program) // => trueChecks whether any entry in the TxHashMap matches the given predicate.
Signature
declare const hasBy: { <K, V>(predicate: (value: V, key: K) => boolean): (self: TxHashMap<K, V>) => Effect<boolean>; <K, V>(self: TxHashMap<K, V>, predicate: (value: V, key: K) => boolean): Effect<boolean>;}Example
(Checking entries with a predicate)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a user status map const currentTime = 1_700_000_000_000 const userStatuses = yield* TxHashMap.make( ["alice", { status: "online", lastSeen: currentTime }], ["bob", { status: "offline", lastSeen: currentTime - 3_600_000 }], ["charlie", { status: "online", lastSeen: currentTime }] )
// Check if any users are online yield* TxHashMap.hasBy( userStatuses, (user) => user.status === "online" ) // => true
// Check if any users have specific username pattern yield* TxHashMap.hasBy( userStatuses, (user, username) => username.startsWith("admin") ) // => false
// Data-last usage with pipe return yield* userStatuses.pipe( TxHashMap.hasBy((user) => currentTime - user.lastSeen < 1_800_000) // 30 minutes )})
await Effect.runPromise(program) // => trueChecks whether the specified key has an entry using a caller-supplied hash.
Gotchas
The supplied hash must be the hash for the same key, such as a precomputed
Hash.hash(key) value. If the hash does not match the key, an existing entry
may not be found.
Signature
declare const hasHash: { <K1, K>(key: K1, hash: number): <V>(self: TxHashMap<K, V>) => Effect<boolean>; <K1, K, V>(self: TxHashMap<K, V>, key: K1, hash: number): Effect<boolean>;}Example
(Checking keys with precomputed hashes)
import { Effect, Hash, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create an access control map const permissions = yield* TxHashMap.make( ["admin", { read: true, write: true, delete: true }], ["user", { read: true, write: false, delete: false }] )
// When checking permissions frequently with same roles const role = "admin" const roleHash = Hash.string(role)
// Use hash-optimized existence check yield* TxHashMap.hasHash(permissions, role, roleHash) // => true
// Check non-existent role yield* TxHashMap.hasHash( permissions, "guest", Hash.string("guest") ) // => false
// Useful in hot paths where hash is computed once and reused const roles = ["admin", "user", "moderator"] const roleHashes = roles.map((role) => [role, Hash.string(role)] as const) const results: Array<string> = [] for (const [role, hash] of roleHashes) { const exists = yield* TxHashMap.hasHash(permissions, role, hash) results.push(`Role ${role}: ${exists}`) } return results})
await Effect.runPromise(program) // => ["Role admin: true", "Role user: true", "Role moderator: false"]Checks whether the TxHashMap is empty.
Signature
declare function isEmpty<K, V>(self: TxHashMap<K, V>): Effect<boolean>Example
(Checking for an empty map)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Start with empty map const cache = yield* TxHashMap.empty<string, any>() yield* TxHashMap.isEmpty(cache) // => true
// Add an item yield* TxHashMap.set(cache, "key1", "value1") yield* TxHashMap.isEmpty(cache) // => false
// Clear and check again yield* TxHashMap.clear(cache) return yield* TxHashMap.isEmpty(cache)})
await Effect.runPromise(program) // => trueisNonEmpty
Checks whether the TxHashMap is non-empty.
Signature
declare function isNonEmpty<K, V>(self: TxHashMap<K, V>): Effect<boolean>Example
(Checking for a non-empty map)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { const inventory = yield* TxHashMap.make(["laptop", 5])
yield* TxHashMap.isNonEmpty(inventory) // => true
// Clear inventory yield* TxHashMap.clear(inventory) return yield* TxHashMap.isNonEmpty(inventory)})
await Effect.runPromise(program) // => falseChecks whether at least one entry in the TxHashMap satisfies the given predicate.
Signature
declare const some: { <K, V>(predicate: (value: V, key: K) => boolean): (self: TxHashMap<K, V>) => Effect<boolean>; <K, V>(self: TxHashMap<K, V>, predicate: (value: V, key: K) => boolean): Effect<boolean>;}Example
(Checking whether some entries match)
import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() { // Create a product inventory const inventory = yield* TxHashMap.make( ["laptop", { price: 999, stock: 5 }], ["mouse", { price: 29, stock: 50 }], ["keyboard", { price: 79, stock: 0 }] )
// Check if any products are expensive yield* TxHashMap.some( inventory, (product) => product.price > 500 ) // => true
// Check if any products are out of stock yield* TxHashMap.some( inventory, (product) => product.stock === 0 ) // => true
// Data-last usage with pipe return yield* inventory.pipe( TxHashMap.some((product) => product.price < 50) )})
await Effect.runPromise(program) // => true