Skip to content

Transactional collections (TxHashMap, TxHashSet, TxChunk)

A bare TxRef holds a single value, but shared state is often a collection: a registry of sessions, an inventory by SKU, an ordered buffer. Effect ships transactional versions of the common data structures — TxHashMap, TxHashSet, and TxChunk — each backed internally by a TxRef, so every operation returns an Effect and participates in the same transaction journal. That means you can read from a map, update a set, and transform a chunk inside one Effect.tx block and have it all commit atomically (or all retry together on conflict).

Two rules cover almost everything:

  • A single operation (TxHashMap.set, TxHashSet.add, TxChunk.append, …) is already its own transaction — no Effect.tx needed.
  • A read-modify-write that must be atomic as a whole (check-then-act, rename, transfer) belongs inside Effect.tx. Because each op is a TxRef read/write, they share one journal and commit together.
import { Context, Effect, Layer, Option, TxHashMap } from "effect"
// A shared inventory keyed by SKU. Multiple fibers reserve stock concurrently;
// each reservation must check availability and decrement atomically.
class Inventory extends Context.Service<Inventory, {
readonly reserve: (sku: string, qty: number) => Effect.Effect<boolean>
readonly stock: (sku: string) => Effect.Effect<number>
}>()("app/Inventory") {
static layer = Layer.effect(Inventory)(
Effect.gen(function*() {
const items = yield* TxHashMap.make(["laptop", 5], ["mouse", 20])
const reserve = Effect.fn("Inventory.reserve")(function*(
sku: string,
qty: number
) {
// The read + check + write happen in one transaction, so two fibers
// can never both pass the availability check for the last unit.
return yield* Effect.tx(
Effect.gen(function*() {
const current = yield* TxHashMap.get(items, sku)
if (Option.isNone(current) || current.value < qty) {
return false
}
yield* TxHashMap.set(items, sku, current.value - qty)
return true
})
)
})
const stock = Effect.fn("Inventory.stock")(function*(sku: string) {
const current = yield* TxHashMap.get(items, sku)
return Option.getOrElse(current, () => 0)
})
return Inventory.of({ reserve, stock })
})
)
}

TxHashMap<K, V> is a transactional key-value map wrapping an immutable HashMap in a TxRef. Reads that may be absent return an Option. Here is the pattern that motivates the type — an atomic read-modify-write across two keys:

import { Effect, TxHashMap } from "effect"
// Atomically rename a key: read the old value, set the new key, drop the old.
// Wrapped in Effect.tx so no other fiber can observe the half-renamed state.
const rename = (
map: TxHashMap.TxHashMap<string, number>,
from: string,
to: string
) =>
Effect.tx(
Effect.gen(function*() {
const value = yield* TxHashMap.get(map, from)
if (value._tag === "Some") {
yield* TxHashMap.set(map, to, value.value)
yield* TxHashMap.remove(map, from)
}
})
)

TxHashMap<K, V> is the map interface; it exposes a ref: TxRef<HashMap<K, V>>. The companion namespace provides type extractors TxHashMap.Key<T>, TxHashMap.Value<T>, and TxHashMap.Entry<T>.

import type { TxHashMap } from "effect"
type M = TxHashMap.TxHashMap<string, number>
type K = TxHashMap.TxHashMap.Key<M> // => string
type V = TxHashMap.TxHashMap.Value<M> // => number
type E = TxHashMap.TxHashMap.Entry<M> // => readonly [string, number]

Creates a map from inline key-value tuples.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["user1", "Alice"], ["user2", "Bob"])
return yield* TxHashMap.size(map) // => 2
})

Creates an empty map; supply the key/value types explicitly.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.empty<string, number>()
return yield* TxHashMap.isEmpty(map) // => true
})

Builds a map from any iterable of [key, value] pairs (arrays, Map, etc.).

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.fromIterable(new Map([["a", 1], ["b", 2]]))
return yield* TxHashMap.size(map) // => 2
})

Type guard: true if the value is a TxHashMap.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["k", "v"])
return [TxHashMap.isTxHashMap(map), TxHashMap.isTxHashMap({})]
// => [true, false]
})

Looks up a key, returning Effect<Option<V>>.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["alice", 30])
const a = yield* TxHashMap.get(map, "alice") // => Option.some(30)
const b = yield* TxHashMap.get(map, "bob") // => Option.none()
})

Like get, but uses a caller-supplied precomputed hash for the key (hot-path optimization). The hash must correspond to the same key.

import { Effect, Hash, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["session", { userId: "u1" }])
const v = yield* TxHashMap.getHash(map, "session", Hash.string("session"))
// => Option.some({ userId: "u1" })
})

Checks whether a key exists, returning Effect<boolean>.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["alice", 1])
return yield* TxHashMap.has(map, "alice") // => true
})

has using a caller-supplied precomputed hash for the key.

import { Effect, Hash, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["admin", true])
return yield* TxHashMap.hasHash(map, "admin", Hash.string("admin")) // => true
})

Checks whether any entry satisfies a predicate over (value, key).

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 10], ["b", 3])
return yield* TxHashMap.hasBy(map, (v) => v > 5) // => true
})

Inserts or overwrites the value for a key. Mutates in place; returns Effect<void>.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["laptop", 5])
yield* TxHashMap.set(map, "laptop", 3)
return yield* TxHashMap.get(map, "laptop") // => Option.some(3)
})

Inserts/overwrites many entries from an iterable at once.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.empty<string, number>()
yield* TxHashMap.setMany(map, [["a", 1], ["b", 2]])
return yield* TxHashMap.size(map) // => 2
})

Applies f to an existing entry, returning the previous value in Some; if the key is absent it returns None and writes nothing.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["downloads", 100])
const prev = yield* TxHashMap.modify(map, "downloads", (n) => n + 1)
// => Option.some(100) (map now holds 101)
const missing = yield* TxHashMap.modify(map, "views", (n) => n + 1)
// => Option.none()
})

Updates, inserts, or removes a key via an Option -> Option function: returning Some upserts the value, None removes any existing entry.

import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["count", 0])
yield* TxHashMap.modifyAt(map, "count", (cur) =>
Option.map(cur, (n) => n + 1))
return yield* TxHashMap.get(map, "count") // => Option.some(1)
})

Removes a key, returning Effect<boolean> indicating whether it existed.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1])
const removed = yield* TxHashMap.remove(map, "a") // => true
const again = yield* TxHashMap.remove(map, "a") // => false
})

Removes every key in an iterable.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 2], ["c", 3])
yield* TxHashMap.removeMany(map, ["a", "b"])
return yield* TxHashMap.size(map) // => 1
})

Removes all entries.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 2])
yield* TxHashMap.clear(map)
return yield* TxHashMap.isEmpty(map) // => true
})

Returns the number of entries.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 2])
return yield* TxHashMap.size(map) // => 2
})

Returns true when the map has no entries.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.empty<string, number>()
return yield* TxHashMap.isEmpty(map) // => true
})

The complement of isEmpty.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1])
return yield* TxHashMap.isNonEmpty(map) // => true
})

Returns an array of all keys.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 2])
return (yield* TxHashMap.keys(map)).sort() // => ["a", "b"]
})

Returns an array of all values.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 2])
return (yield* TxHashMap.values(map)).sort() // => [1, 2]
})

Returns an array of all [key, value] pairs.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1])
return yield* TxHashMap.entries(map) // => [["a", 1]]
})

Alias for entries, for API parity with HashMap.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1])
return yield* TxHashMap.toEntries(map) // => [["a", 1]]
})

Alias for values, for API parity with HashMap.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 2])
return (yield* TxHashMap.toValues(map)).sort() // => [1, 2]
})

Returns the current contents as an immutable HashMap — a stable copy you can read with plain HashMap operations even as the TxHashMap keeps changing.

import { Effect, HashMap, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["temp", 22])
const snap = yield* TxHashMap.snapshot(map)
yield* TxHashMap.set(map, "temp", 23)
return HashMap.get(snap, "temp") // => Option.some(22) (snapshot frozen)
})

Runs an effectful function for each entry; returns Effect<void>.

import { Console, Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 2])
yield* TxHashMap.forEach(map, (value, key) => Console.log(`${key}=${value}`))
// => logs "a=1" and "b=2"
})

Transforms every value (receiving (value, key)), returning a new TxHashMap; the original is unchanged.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const ages = yield* TxHashMap.make(["alice", 30], ["bob", 25])
const doubled = yield* TxHashMap.map(ages, (age) => age * 2)
return yield* TxHashMap.get(doubled, "alice") // => Option.some(60)
})

Keeps only entries whose (value, key) satisfy the predicate, returning a new TxHashMap.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 5], ["c", 9])
const big = yield* TxHashMap.filter(map, (v) => v > 4)
return yield* TxHashMap.size(big) // => 2
})

Filters and maps at once: f returns a ResultResult.succeed(x) keeps the transformed value, Result.failVoid drops the entry. Returns a new TxHashMap.

import { Effect, Result, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const raw = yield* TxHashMap.make(["a", "30"], ["b", "x"])
const nums = yield* TxHashMap.filterMap(raw, (s) => {
const n = parseInt(s)
return isNaN(n) ? Result.failVoid : Result.succeed(n)
})
return yield* TxHashMap.get(nums, "a") // => Option.some(30) ("b" dropped)
})

Given a map of Option values, drops the Nones and unwraps the Somes into a new TxHashMap.

import { Effect, Option, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(
["a", Option.some(1)],
["b", Option.none<number>()]
)
const clean = yield* TxHashMap.compact(map)
return yield* TxHashMap.size(clean) // => 1
})

Maps each entry to a TxHashMap (effectfully) and merges the results into a new TxHashMap.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const teams = yield* TxHashMap.make(["eng", ["alice", "bob"]])
const people = yield* TxHashMap.flatMap(teams, (members, team) =>
Effect.gen(function*() {
const out = yield* TxHashMap.empty<string, string>()
for (const m of members) yield* TxHashMap.set(out, m, team)
return out
}))
return yield* TxHashMap.get(people, "alice") // => Option.some("eng")
})

Folds all entries into a single value with (acc, value, key) => acc.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const sales = yield* TxHashMap.make(["q1", 100], ["q2", 200])
return yield* TxHashMap.reduce(sales, 0, (total, amt) => total + amt) // => 300
})

Returns the first [key, value] entry matching the predicate, as an Option.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 9])
return yield* TxHashMap.findFirst(map, (v) => v > 5)
// => Option.some(["b", 9])
})

true if at least one entry matches the predicate.

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 1], ["b", 9])
return yield* TxHashMap.some(map, (v) => v > 5) // => true
})

true if all entries match the predicate (vacuously true when empty).

import { Effect, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const map = yield* TxHashMap.make(["a", 2], ["b", 4])
return yield* TxHashMap.every(map, (v) => v % 2 === 0) // => true
})

Merges another immutable HashMap into this TxHashMap, with the other map’s values winning on key collisions. Mutates in place.

import { Effect, HashMap, TxHashMap } from "effect"
const program = Effect.gen(function*() {
const prefs = yield* TxHashMap.make(["theme", "light"])
yield* TxHashMap.union(prefs, HashMap.make(["theme", "dark"], ["lang", "en"]))
return yield* TxHashMap.get(prefs, "theme") // => Option.some("dark")
})

TxHashSet<V> is the transactional set, wrapping an immutable HashSet. It is ideal for membership that several fibers update — active connections, seen ids, a set of locked resources. The check-then-claim pattern below is the canonical use:

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const active = yield* TxHashSet.empty<string>()
// Try to claim a slot only if it isn't already taken — atomically.
const claim = (id: string) =>
Effect.tx(
Effect.gen(function*() {
if (yield* TxHashSet.has(active, id)) {
return false
}
yield* TxHashSet.add(active, id)
return true
})
)
return { claimed: yield* claim("session-1"), again: yield* claim("session-1") }
// => { claimed: true, again: false }
})

TxHashSet<V> exposes a ref: TxRef<HashSet<V>>. The namespace provides the TxHashSet.Value<T> extractor.

import type { TxHashSet } from "effect"
type S = TxHashSet.TxHashSet<string>
type V = TxHashSet.TxHashSet.Value<S> // => string

Creates a set from a variable list of values (duplicates collapse).

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make(1, 2, 2, 3)
return yield* TxHashSet.size(set) // => 3
})

Creates an empty set.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.empty<string>()
return yield* TxHashSet.isEmpty(set) // => true
})

Builds a set from any iterable.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.fromIterable(["a", "b", "a"])
return yield* TxHashSet.size(set) // => 2
})

Wraps an existing immutable HashSet in a transactional set.

import { Effect, HashSet, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.fromHashSet(HashSet.make("x", "y"))
return yield* TxHashSet.size(set) // => 2
})

Returns an immutable HashSet snapshot of the current contents.

import { Effect, HashSet, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make("x", "y")
const snap = yield* TxHashSet.toHashSet(set)
return HashSet.size(snap) // => 2
})

Type guard for TxHashSet.

import { Effect, HashSet, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make(1)
return [TxHashSet.isTxHashSet(set), TxHashSet.isTxHashSet(HashSet.make(1))]
// => [true, false]
})

Adds a value (no-op if already present). Mutates in place.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make("a")
yield* TxHashSet.add(set, "b")
return yield* TxHashSet.size(set) // => 2
})

Removes a value, returning Effect<boolean> for whether it was present.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make("a", "b")
return yield* TxHashSet.remove(set, "b") // => true
})

Membership check; uses Equal/Hash so custom value types work too.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make("a", "b")
return yield* TxHashSet.has(set, "a") // => true
})

Returns the number of values.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make("a", "b")
return yield* TxHashSet.size(set) // => 2
})

true when the set has no values.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.empty<string>()
return yield* TxHashSet.isEmpty(set) // => true
})

Removes all values. Mutates in place.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make("a", "b")
yield* TxHashSet.clear(set)
return yield* TxHashSet.isEmpty(set) // => true
})

Maps each value, returning a new TxHashSet (size may shrink if the function produces duplicates).

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make(1, 2, 3)
const doubled = yield* TxHashSet.map(set, (n) => n * 2)
return (Array.from(yield* TxHashSet.toHashSet(doubled))).sort() // => [2, 4, 6]
})

Keeps only values satisfying the predicate, returning a new TxHashSet.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make(1, 2, 3, 4)
const evens = yield* TxHashSet.filter(set, (n) => n % 2 === 0)
return yield* TxHashSet.size(evens) // => 2
})

Folds all values into a single accumulator.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make(1, 2, 3, 4)
return yield* TxHashSet.reduce(set, 0, (acc, n) => acc + n) // => 10
})

true if at least one value matches the predicate.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make(1, 2, 3)
return yield* TxHashSet.some(set, (n) => n > 2) // => true
})

true if every value matches (vacuously true when empty).

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const set = yield* TxHashSet.make(2, 4, 6)
return yield* TxHashSet.every(set, (n) => n % 2 === 0) // => true
})

Returns a new TxHashSet containing values from both sets.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const a = yield* TxHashSet.make("a", "b")
const b = yield* TxHashSet.make("b", "c")
const u = yield* TxHashSet.union(a, b)
return yield* TxHashSet.size(u) // => 3
})

Returns a new TxHashSet of values present in both sets.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const a = yield* TxHashSet.make("a", "b", "c")
const b = yield* TxHashSet.make("b", "c", "d")
const i = yield* TxHashSet.intersection(a, b)
return yield* TxHashSet.size(i) // => 2
})

Returns a new TxHashSet of values in the first set but not the second.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const a = yield* TxHashSet.make("a", "b", "c")
const b = yield* TxHashSet.make("b", "d")
const d = yield* TxHashSet.difference(a, b)
return yield* TxHashSet.size(d) // => 2 ("a" and "c")
})

true if every value of the first set is contained in the second.

import { Effect, TxHashSet } from "effect"
const program = Effect.gen(function*() {
const small = yield* TxHashSet.make("a", "b")
const large = yield* TxHashSet.make("a", "b", "c")
return yield* TxHashSet.isSubset(small, large) // => true
})

TxChunk<A> is a transactional, ordered sequence backed by an immutable Chunk. Use it as a transactional buffer or log when you need indexed, ordered access rather than map/set semantics. Most operations mutate the stored chunk in place (returning Effect<void>); get returns the whole current Chunk and modify returns a value you compute.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const buffer = yield* TxChunk.empty<string>()
// Two appends commit together: a reader never sees just "a".
yield* Effect.tx(
Effect.gen(function*() {
yield* TxChunk.append(buffer, "a")
yield* TxChunk.append(buffer, "b")
})
)
const all = yield* TxChunk.get(buffer)
return Chunk.toReadonlyArray(all) // => ["a", "b"]
})

TxChunk<A> exposes a ref: TxRef<Chunk<A>>.

import type { TxChunk } from "effect"
type C = TxChunk.TxChunk<number>

Creates a TxChunk from an existing immutable Chunk.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.make(Chunk.fromIterable([1, 2, 3]))
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [1, 2, 3]
})

Creates an empty TxChunk.

import { Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.empty<number>()
return yield* TxChunk.isEmpty(c) // => true
})

Creates a TxChunk from any iterable.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3])
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [1, 2, 3]
})

Wraps an already-constructed TxRef<Chunk<A>> (advanced; no Effect needed).

import { Chunk, TxChunk, TxRef } from "effect"
const ref = TxRef.makeUnsafe(Chunk.fromIterable([1, 2, 3]))
const c = TxChunk.makeUnsafe(ref)

Reads the current chunk; the access is tracked for conflict detection.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3])
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [1, 2, 3]
})

Replaces the entire stored chunk. Mutates in place.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3])
yield* TxChunk.set(c, Chunk.fromIterable([9, 9]))
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [9, 9]
})

Returns the element count.

import { Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3])
return yield* TxChunk.size(c) // => 3
})

true when the chunk has no elements.

import { Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.empty<number>()
return yield* TxChunk.isEmpty(c) // => true
})

The complement of isEmpty.

import { Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1])
return yield* TxChunk.isNonEmpty(c) // => true
})

Appends one element to the end. Mutates in place.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3])
yield* TxChunk.append(c, 4)
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [1, 2, 3, 4]
})

Appends all elements of another immutable Chunk to the end.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2])
yield* TxChunk.appendAll(c, Chunk.fromIterable([3, 4]))
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [1, 2, 3, 4]
})

Prepends one element to the beginning. Mutates in place.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([2, 3])
yield* TxChunk.prepend(c, 1)
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [1, 2, 3]
})

Prepends all elements of another immutable Chunk to the beginning.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([3, 4])
yield* TxChunk.prependAll(c, Chunk.fromIterable([1, 2]))
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [1, 2, 3, 4]
})

Appends the contents of another TxChunk to the end of this one (the other is read transactionally and left unchanged).

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const a = yield* TxChunk.fromIterable([1, 2])
const b = yield* TxChunk.fromIterable([3, 4])
yield* TxChunk.concat(a, b)
return Chunk.toReadonlyArray(yield* TxChunk.get(a)) // => [1, 2, 3, 4]
})

Keeps only the first n elements. Mutates in place.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3, 4, 5])
yield* TxChunk.take(c, 3)
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [1, 2, 3]
})

Removes the first n elements. Mutates in place.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3, 4, 5])
yield* TxChunk.drop(c, 2)
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [3, 4, 5]
})

Keeps elements from start (inclusive) to end (exclusive). Mutates in place.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3, 4, 5, 6, 7])
yield* TxChunk.slice(c, 2, 5)
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [3, 4, 5]
})

Transforms each element with a function returning the same element type. Mutates in place.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3])
yield* TxChunk.map(c, (n) => n * 2)
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [2, 4, 6]
})

Keeps only elements satisfying the predicate. Mutates in place.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3, 4, 5, 6])
yield* TxChunk.filter(c, (n) => n % 2 === 0)
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [2, 4, 6]
})

Atomically reads the current chunk and replaces it, returning a computed value — the chunk equivalent of TxRef.modify. f returns [returnValue, newChunk].

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3])
const oldSize = yield* TxChunk.modify(c, (cur) => [
Chunk.size(cur), // => returned: 3
Chunk.append(cur, 4) // new stored value
])
// oldSize === 3; chunk now [1, 2, 3, 4]
})

Replaces the stored chunk with f(current), returning Effect<void> — like modify without a return value.

import { Chunk, Effect, TxChunk } from "effect"
const program = Effect.gen(function*() {
const c = yield* TxChunk.fromIterable([1, 2, 3])
yield* TxChunk.update(c, (cur) => Chunk.reverse(cur))
return Chunk.toReadonlyArray(yield* TxChunk.get(c)) // => [3, 2, 1]
})
You need…Use
A single atomic valueTxRef
Keyed lookup / registryTxHashMap
Membership trackingTxHashSet
Ordered, indexed bufferTxChunk
Producer/consumer with blockingTxQueue / TxPubSub
State you can subscribe toTxSubscriptionRef
Permits, locks, one-shot signalscoordination primitives

All of these follow the same pattern: every operation returns an Effect and composes inside Effect.tx, so you can mix maps, sets, chunks, queues, and plain TxRefs in a single atomic transaction.