Import
import { Sink } from "@typed/fx/Sink";Access Sink.WithStateSemaphore through the imported Sink export. Its declaration below describes the member.
Signatures
interface WithStateSemaphore<A, E, R, B> extends WithEarlyExit<A, E, R> {
readonly modifyEffect: <C, E2, R2>(f: (state: B) => Effect<readonly [
C,
B
], E2, R2>) => Effect<C, E | E2, R | R2>;
readonly updateEffect: <E2, R2>(f: (state: B) => Effect<B, E2, R2>) => Effect<B, E | E2, R | R2>;
readonly get: Effect<B, E, R>;
}Why
Effectful reducers may overlap; semaphore-guarded operations prevent lost updates while keeping their typed errors and service requirements visible.
Ownership and lifetime
withStateSemaphore owns the mutable cell and semaphore for one invocation. Each modify/update
holds one permit until its effect completes or is interrupted, then releases it automatically.
Property: get
Reads the current state under the same semaphore as updates.
Property: get: Why
Locked reads cannot observe an in-progress effectful transition.
Property: get: Ownership and lifetime
The read holds one permit briefly and acquires no resource beyond the invocation-owned semaphore.
Property: modifyEffect
Atomically derives a result and replacement state under the sink’s semaphore.
Property: modifyEffect: Why
Returning a separate result avoids a second unlocked read after an update.
Property: modifyEffect: Ownership and lifetime
One semaphore permit is held for the entire Effect and released on completion or interruption. The state changes only when the Effect succeeds.
Property: updateEffect
Atomically replaces state and returns the replacement value.
Property: updateEffect: Why
It is the direct serialized form of an effectful state transition.
Property: updateEffect: Ownership and lifetime
One semaphore permit is held until the transition completes or is interrupted. Failure leaves the state unchanged.
Examples
import { Effect } from "effect"
import type * as Sink from "@typed/fx/Sink"
const increment = (sink: Sink.Sink.WithStateSemaphore<number, never, never, number>) =>
sink.updateEffect((n) => Effect.succeed(n + 1))Other public imports
These import paths expose the same declaration. Each page retains its own public name and signature.