Ref.ts
Ref.ts overview
Section titled “Ref.ts overview”Stores fiber-safe mutable state inside Effect programs.
A Ref<A> holds one value and exposes reads, writes, and atomic
transformations as effects, so state changes compose with Effect’s
concurrency model. This module includes constructors, safe and unsafe reads,
set and get-and-set helpers, update and modify helpers, and conditional
update variants that leave the value unchanged when an Option.none result
is returned.
Since v2.0.0
Exports Grouped by Category
Section titled “Exports Grouped by Category”constructors
Section titled “constructors”Creates a new Ref with the specified initial value.
When to use
Use to create a Ref for shared mutable state inside an Effect program.
Example (Creating a ref)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const ref = yield* Ref.make(42) const value = yield* Ref.get(ref) console.log(value) // 42})See
makeUnsafefor synchronous construction outside Effect code
Signature
declare const make: <A>(value: A) => Effect.Effect<Ref<A>>Since v2.0.0
makeUnsafe
Section titled “makeUnsafe”Creates a new Ref with the specified initial value (unsafe version).
When to use
Use when you need immediate synchronous construction and can guarantee
that creating the Ref outside of Effect is safe.
Gotchas
Prefer Ref.make for Effect-wrapped creation in Effect programs.
Example (Creating a ref unsafely)
import { Ref } from "effect"
// Create a ref directly without Effectconst counter = Ref.makeUnsafe(0)
// Get the current valueconst value = Ref.getUnsafe(counter)console.log(value) // 0
// Note: This is unsafe and should be used carefully// Prefer Ref.make for Effect-wrapped creationSignature
declare const makeUnsafe: <A>(value: A) => Ref<A>Since v4.0.0
getters
Section titled “getters”Gets the current value of the Ref.
When to use
Use to read the current Ref value without changing it.
Example (Getting the current value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const ref = yield* Ref.make(42) const value = yield* Ref.get(ref) console.log(value) // 42})See
setfor replacing the current value
Signature
declare const get: <A>(self: Ref<A>) => Effect.Effect<A, never, never>Since v2.0.0
getUnsafe
Section titled “getUnsafe”Gets the current value of the Ref synchronously (unsafe version).
When to use
Use when you need immediate synchronous access and can guarantee that
reading the Ref outside of Effect is safe.
Gotchas
Prefer Ref.get for Effect-wrapped access in Effect programs.
Example (Reading a ref unsafely)
import { Ref } from "effect"
// Create a ref directlyconst counter = Ref.makeUnsafe(42)
// Get the value synchronouslyconst value = Ref.getUnsafe(counter)console.log(value) // 42
// Note: This is unsafe and should be used carefully// Prefer Ref.get for Effect-wrapped accessSignature
declare const getUnsafe: <A>(self: Ref<A>) => ASince v4.0.0
models
Section titled “models”Ref (interface)
Section titled “Ref (interface)”A mutable reference that provides atomic read, write, and update operations.
When to use
Use to keep shared mutable state that is read and updated inside Effect programs.
Details
A Ref is a thread-safe mutable reference type for shared state. It supports
simple read and write operations as well as atomic transformations.
Example (Reading and updating a ref)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { // Create a ref with initial value const counter = yield* Ref.make(0)
// Read the current value const value = yield* Ref.get(counter) console.log(value) // 0
// Update the value atomically yield* Ref.update(counter, (n) => n + 1)
// Read the updated value const newValue = yield* Ref.get(counter) console.log(newValue) // 1})See
makefor creating aRefgetfor reading the current valuesetfor replacing the current value
Signature
export interface Ref<in out A> extends Ref.Variance<A>, Pipeable { readonly ref: MutableRef.MutableRef<A>}Since v2.0.0
mutations
Section titled “mutations”getAndSet
Section titled “getAndSet”Gets the current value of the Ref, sets it to the specified value, and returns the previous value atomically.
When to use
Use to replace a plain Ref value while returning the previous value.
Example (Replacing a value atomically)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const ref = yield* Ref.make("initial")
// Get current value and set new value atomically const previous = yield* Ref.getAndSet(ref, "updated") console.log(previous) // "initial"
const current = yield* Ref.get(ref) console.log(current) // "updated"})See
setfor setting without returning the previous valuegetAndUpdatefor deriving the new value from the previous value
Signature
declare const getAndSet: (<A>(value: A) => (self: Ref<A>) => Effect.Effect<A>) & (<A>(self: Ref<A>, value: A) => Effect.Effect<A>)Since v2.0.0
getAndUpdate
Section titled “getAndUpdate”Gets the current value of the Ref, updates it with the given function, and returns the previous value atomically.
When to use
Use to derive a new Ref value while returning the previous value.
Example (Updating and returning the previous value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const counter = yield* Ref.make(10)
// Get current value and update it atomically const previous = yield* Ref.getAndUpdate(counter, (n) => n * 2) console.log(previous) // 10
const current = yield* Ref.get(counter) console.log(current) // 20})See
updatefor updating without returning the previous valueupdateAndGetfor returning the new value instead
Signature
declare const getAndUpdate: (<A>(f: (a: A) => A) => (self: Ref<A>) => Effect.Effect<A>) & (<A>(self: Ref<A>, f: (a: A) => A) => Effect.Effect<A>)Since v2.0.0
getAndUpdateSome
Section titled “getAndUpdateSome”Gets the current value of the Ref and updates it atomically with the given partial function.
When to use
Use to return the previous Ref value while applying a conditional update.
Details
If the partial function returns Option.some, the Ref is updated with the
new value. If it returns Option.none, the Ref is left unchanged. The effect
always returns the value that was in the Ref before the attempted update.
Example (Conditionally updating and returning the previous value)
import { Effect, Option, Ref } from "effect"
const program = Effect.gen(function* () { const counter = yield* Ref.make(5)
// Only update if value is greater than 3 const previous1 = yield* Ref.getAndUpdateSome(counter, (n) => (n > 3 ? Option.some(n * 2) : Option.none())) console.log(previous1) // 5
const current1 = yield* Ref.get(counter) console.log(current1) // 10
// Try to update again (won't update since 10 > 3 is true but let's say condition is n < 3) const previous2 = yield* Ref.getAndUpdateSome(counter, (n) => (n < 3 ? Option.some(n * 2) : Option.none())) console.log(previous2) // 10
const current2 = yield* Ref.get(counter) console.log(current2) // 10 (unchanged)})See
getAndUpdatefor always applying an updateupdateSomefor conditional updates without returning the previous value
Signature
declare const getAndUpdateSome: (<A>(pf: (a: A) => Option.Option<A>) => (self: Ref<A>) => Effect.Effect<A>) & (<A>(self: Ref<A>, pf: (a: A) => Option.Option<A>) => Effect.Effect<A>)Since v2.0.0
setAndGet
Section titled “setAndGet”Sets the value of the Ref atomically to the specified value and returns the new value.
When to use
Use when you want to set a Ref value and immediately get it back in one
atomic operation.
Example (Setting and returning the new value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const ref = yield* Ref.make(10)
// Set new value and get it back in one operation const newValue = yield* Ref.setAndGet(ref, 42) console.log(newValue) // 42
// Verify the ref contains the new value const current = yield* Ref.get(ref) console.log(current) // 42})
// Useful for sequential operationsconst program2 = Effect.gen(function* () { const counter = yield* Ref.make(0)
const newValue = yield* Ref.setAndGet(counter, 20) console.log(newValue) // 20})Signature
declare const setAndGet: (<A>(value: A) => (self: Ref<A>) => Effect.Effect<A>) & (<A>(self: Ref<A>, value: A) => Effect.Effect<A>)Since v2.0.0
updateAndGet
Section titled “updateAndGet”Updates the value of the Ref atomically using the given function and returns the new value.
When to use
Use to apply a Ref state transition and return the new stored value.
Example (Updating and returning the new value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const counter = yield* Ref.make(5)
// Update and get the new value in one operation const newValue = yield* Ref.updateAndGet(counter, (n) => n * 3) console.log(newValue) // 15
// Verify the ref contains the new value const current = yield* Ref.get(counter) console.log(current) // 15})See
updatefor updating without returning the new valuegetAndUpdatefor returning the previous value instead
Signature
declare const updateAndGet: (<A>(f: (a: A) => A) => (self: Ref<A>) => Effect.Effect<A>) & (<A>(self: Ref<A>, f: (a: A) => A) => Effect.Effect<A>)Since v2.0.0
updateSomeAndGet
Section titled “updateSomeAndGet”Updates the value of the Ref atomically using the given partial function and returns the current value.
When to use
Use to apply a conditional Ref update and return the resulting current
value.
Details
If the partial function returns Option.some, the Ref is updated with the
new value. If it returns Option.none, the Ref is left unchanged. The effect
returns the current value of the Ref after the potential update.
Example (Conditionally updating and returning the current value)
import { Effect, Option, Ref } from "effect"
const program = Effect.gen(function* () { const counter = yield* Ref.make(10)
// Only update if value is greater than 5 const result1 = yield* Ref.updateSomeAndGet(counter, (n) => (n > 5 ? Option.some(n / 2) : Option.none())) console.log(result1) // 5 (updated and returned)
// Try to update again with same condition const result2 = yield* Ref.updateSomeAndGet(counter, (n) => (n > 5 ? Option.some(n / 2) : Option.none())) console.log(result2) // 5 (unchanged because 5 is not > 5)})See
updateSomefor conditional updates without returning a valueupdateAndGetfor always updating and returning the new value
Signature
declare const updateSomeAndGet: (<A>(pf: (a: A) => Option.Option<A>) => (self: Ref<A>) => Effect.Effect<A>) & (<A>(self: Ref<A>, pf: (a: A) => Option.Option<A>) => Effect.Effect<A>)Since v2.0.0
setters
Section titled “setters”modify
Section titled “modify”Modifies the value of the Ref atomically using the given function.
When to use
Use to compute both a separate return value and the next stored Ref value
in one atomic update.
Details
The function receives the current value and returns a tuple of
[result, newValue]. The Ref is updated with newValue, and result is
returned by the effect.
Example (Modifying a value atomically)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const counter = yield* Ref.make(10)
// Modify the ref and return some computation result const result = yield* Ref.modify(counter, (n) => [ `Previous value was ${n}`, // Return value n * 2 // New ref value ])
console.log(result) // "Previous value was 10"
const current = yield* Ref.get(counter) console.log(current) // 20})
// Example with more complex computationconst program2 = Effect.gen(function* () { const state = yield* Ref.make({ count: 0, total: 0 })
const incremented = yield* Ref.modify(state, (s) => [ s.count, // Return previous count { count: s.count + 1, total: s.total + s.count + 1 } // New state ])
console.log(incremented) // 0})See
updateAndGetfor returning the new stored valuemodifySomefor optionally updating while returning a separate result
Signature
declare const modify: (<A, B>(f: (a: A) => readonly [B, A]) => (self: Ref<A>) => Effect.Effect<B>) & (<A, B>(self: Ref<A>, f: (a: A) => readonly [B, A]) => Effect.Effect<B>)Since v2.0.0
modifySome
Section titled “modifySome”Computes a result atomically and optionally updates the value of the Ref.
When to use
Use to compute a return value while optionally updating a plain Ref.
Details
The callback receives the current value and returns [result, nextValue],
where nextValue is an Option. If nextValue is Option.some(value),
the Ref is updated to value; if it is Option.none(), the Ref is left
unchanged. The returned effect always succeeds with result.
Example (Conditionally modifying a value)
import { Effect, Option, Ref } from "effect"
const program = Effect.gen(function* () { const counter = yield* Ref.make(5)
// Only modify if value is greater than 3 const result1 = yield* Ref.modifySome(counter, (n) => n > 3 ? [`incremented ${n}`, Option.some(n + 10)] : ["no change", Option.none()] )
console.log(result1) // "incremented 5"
const current1 = yield* Ref.get(counter) console.log(current1) // 15
// Try to modify with a condition that fails const result2 = yield* Ref.modifySome(counter, (n) => n < 10 ? [`decremented ${n}`, Option.some(n - 5)] : ["no change", Option.none()] )
console.log(result2) // "no change"
const current2 = yield* Ref.get(counter) console.log(current2) // 15 (unchanged)})See
modifyfor always storing a new valueupdateSomefor optional updates without a separate return value
Signature
declare const modifySome: { <B, A>(pf: (a: A) => readonly [B, Option.Option<A>]): (self: Ref<A>) => Effect.Effect<B> <A, B>(self: Ref<A>, pf: (a: A) => readonly [B, Option.Option<A>]): Effect.Effect<B>}Since v2.0.0
Sets the value of the Ref to the specified value.
When to use
Use to replace the current Ref value with a known value.
Example (Setting a value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const ref = yield* Ref.make(0) yield* Ref.set(ref, 42) const value = yield* Ref.get(ref) console.log(value) // 42})
// Using multiple operationsconst program2 = Effect.gen(function* () { const ref = yield* Ref.make(0) yield* Ref.set(ref, 100) const value = yield* Ref.get(ref) console.log(value) // 100})See
getAndSetfor setting while returning the previous valuesetAndGetfor setting while returning the new value
Signature
declare const set: (<A>(value: A) => (self: Ref<A>) => Effect.Effect<void>) & (<A>(self: Ref<A>, value: A) => Effect.Effect<void>)Since v2.0.0
update
Section titled “update”Updates the value of the Ref atomically using the given function.
When to use
Use to apply a Ref state transition without returning a value.
Example (Updating a value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () { const counter = yield* Ref.make(5)
// Update the value yield* Ref.update(counter, (n) => n * 2)
const value = yield* Ref.get(counter) console.log(value) // 10})
// Using multiple operationsconst program2 = Effect.gen(function* () { const counter = yield* Ref.make(5) yield* Ref.update(counter, (n: number) => n + 10) const value = yield* Ref.get(counter) console.log(value) // 15})See
updateAndGetfor returning the new valuegetAndUpdatefor returning the previous value
Signature
declare const update: (<A>(f: (a: A) => A) => (self: Ref<A>) => Effect.Effect<void>) & (<A>(self: Ref<A>, f: (a: A) => A) => Effect.Effect<void>)Since v2.0.0
updateSome
Section titled “updateSome”Updates the value of the Ref atomically using the given partial function.
When to use
Use to apply a conditional Ref update without returning a value.
Details
If the partial function returns Option.some, the Ref is updated with the
new value. If it returns Option.none, the Ref is left unchanged.
Example (Conditionally updating a value)
import { Effect, Option, Ref } from "effect"
const program = Effect.gen(function* () { const counter = yield* Ref.make(5)
// Only update if value is even yield* Ref.updateSome(counter, (n) => (n % 2 === 0 ? Option.some(n * 2) : Option.none()))
let current = yield* Ref.get(counter) console.log(current) // 5 (unchanged because 5 is odd)
// Set to even number and try again yield* Ref.set(counter, 6) yield* Ref.updateSome(counter, (n) => (n % 2 === 0 ? Option.some(n * 2) : Option.none()))
current = yield* Ref.get(counter) console.log(current) // 12 (updated because 6 is even)})See
updatefor always applying an updateupdateSomeAndGetfor returning the resulting current value
Signature
declare const updateSome: (<A>(f: (a: A) => Option.Option<A>) => (self: Ref<A>) => Effect.Effect<void>) & (<A>(self: Ref<A>, f: (a: A) => Option.Option<A>) => Effect.Effect<void>)Since v2.0.0
Ref (namespace)
Section titled “Ref (namespace)”The Ref namespace containing type definitions and utilities.
When to use
Use when referring to type members nested under the Ref namespace.
Since v2.0.0
Variance (interface)
Section titled “Variance (interface)”Variance interface for Ref types, defining the type parameter constraints.
When to use
Use when working with the type-level variance marker carried by Ref.
Example (Using invariant refs)
import { Effect, Ref } from "effect"
// This interface defines the invariant nature of Ref's type parameter// A Ref<A> is both a producer and consumer of Aconst program = Effect.gen(function* () { const ref = yield* Ref.make(42)
// Ref is invariant - it can both produce and consume numbers const value = yield* Ref.get(ref) // produces number yield* Ref.set(ref, value + 1) // consumes number})Signature
export interface Variance<in out A> { readonly [TypeId]: { readonly _A: Invariant<A> }}Since v2.0.0