Skip to content

Optic.ts

Reads and updates focused parts of values without mutating the original value.

An optic describes where to look inside a value, such as a record field, a union variant, an optional value, or several values in a collection. Different optic types describe different kinds of focus: some always find a value, some may not, and some can find many. This module includes the optic types, constructors, focusing helpers, and operations for replacing, modifying, or collecting focused values.

Since v4.0.0



A lossless, reversible conversion between types S and A.

When to use

Use when you have a pair of functions that convert back and forth without losing information (e.g. Record ↔ entries, Celsius ↔ Fahrenheit).

  • You want the strongest optic that can be composed with any other.

Details

  • get(s) always succeeds and returns an A.
  • set(a) always succeeds and returns an S.
  • get(set(a)) === a and set(get(s)) equals s (round-trip laws).
  • Extends both Lens and Prism.

Example (Converting between Celsius and Fahrenheit)

import { Optic } from "effect"
const fahrenheit = Optic.makeIso<number, number>(
(c) => (c * 9) / 5 + 32,
(f) => ((f - 32) * 5) / 9
)
console.log(fahrenheit.get(100))
// Output: 212
console.log(fahrenheit.set(32))
// Output: 0

See

  • makeIso — constructor
  • Lens — when you only need a one-directional focus into a whole
  • Prism — when the focus may not be present

Signature

export interface Iso<in out S, in out A> extends Lens<S, A>, Prism<S, A> {}

Source

Since v4.0.0

Iso that converts a Record<string, A> to an array of [key, value] entries and back.

When to use

Use when you want to traverse or manipulate record entries as an array (e.g. with .forEach()).

Details

  • get uses Object.entries.
  • set uses Object.fromEntries.
  • Round-trip is lossless for Record<string, A>.

Example (Traversing record values)

import { Optic, Schema } from "effect"
const _positiveValues = Optic.entries<number>().forEach((entry) => entry.key(1).check(Schema.isGreaterThan(0)))
const inc = _positiveValues.modifyAll((n) => n + 1)
console.log(inc({ a: 0, b: 3, c: -1 }))
// Output: { a: 0, b: 4, c: -1 }

See

  • Iso — the type this function returns
  • id — identity iso

Signature

declare const entries: <A>() => Iso<Record<string, A>, ReadonlyArray<readonly [string, A]>>

Source

Since v4.0.0

Iso that focuses on the whole value unchanged.

When to use

Use when you need to start an optic chain with a focus on the whole value.

Details

  • get(s) returns s.
  • set(a) returns a.
  • Singleton — every call returns the same instance.

Example (Starting an optic chain)

import { Optic } from "effect"
type S = { readonly x: number }
const _x = Optic.id<S>().key("x")
console.log(_x.get({ x: 42 }))
// Output: 42

See

  • Iso — the type this function returns

Signature

declare const id: <S>() => Iso<S, S>

Source

Since v4.0.0

Focuses on exactly one part A inside a whole S.

When to use

Use when you always have a value to read and need the original S to produce the updated whole, unlike Iso.

Details

  • get(s) always succeeds and returns A.
  • replace(a, s) returns a new S with the focused part replaced.
  • Extends Optional.
  • Composing a Lens with a Prism or Optional produces an Optional.

Example (Focusing on a struct field)

import { Optic } from "effect"
type Person = { readonly name: string; readonly age: number }
const _name = Optic.id<Person>().key("name")
console.log(_name.get({ name: "Alice", age: 30 }))
// Output: "Alice"

See

  • makeLens — constructor
  • Iso — when conversion is lossless in both directions
  • Optional — when reading can also fail

Signature

export interface Lens<in out S, in out A> extends Optional<S, A> {
readonly get: (s: S) => A
}

Source

Since v4.0.0

The most general optic — both reading and writing can fail.

When to use

Use when the focus may not exist in S and writing a new A back may also fail, for example when the source no longer matches the expected shape. This is the base type extended by Iso, Lens, Prism, and Traversal.

Details

  • getResult(s) returns Result.Success<A> or Result.Failure<string>.
  • replaceResult(a, s) returns Result.Success<S> or Result.Failure<string>.
  • replace(a, s) returns the original s on failure (never throws).
  • modify(f) returns the original s on failure (never throws).
  • All operations are pure; inputs are never mutated.

Example (Focusing on an optional record key)

import { Optic, Result } from "effect"
type Env = { [key: string]: string }
const _home = Optic.id<Env>().at("HOME")
console.log(Result.isSuccess(_home.getResult({ HOME: "/root" })))
// Output: true
console.log(Result.isFailure(_home.getResult({ PATH: "/bin" })))
// Output: true
// replace returns original on failure
console.log(_home.replace("/new", { PATH: "/bin" }))
// Output: { PATH: "/bin" }

See

  • makeOptional — constructor
  • Lens — when reading always succeeds
  • Prism — when writing always succeeds

Signature

export interface Optional<in out S, in out A> {
readonly node: Node
/**
* Attempts to read the focus `A` from the whole `S`. Returns
* `Result.Success<A>` when the focus exists, or
* `Result.Failure<string>` with a descriptive error otherwise.
*/
readonly getResult: (s: S) => Result.Result<A, string>
/**
* Replaces the focus in `S` with a new `A`. Returns the original `s`
* unchanged when the optic cannot focus (never throws).
*/
readonly replace: (a: A, s: S) => S
/**
* Like {@link replace}, but returns an explicit `Result` so callers can
* detect and handle failure.
*/
readonly replaceResult: (a: A, s: S) => Result.Result<S, string>
/**
* Composes this optic with another. The result type is the weakest of
* the two: Iso + Iso = Iso, Lens + Prism = Optional, etc.
*
* **Example** (Composing a lens with a prism)
*
* ```ts
* import { Optic, Option } from "effect"
*
* type State = { value: Option.Option<number> }
*
* const _inner = Optic.id<State>().key("value").compose(Optic.some())
* // _inner is Optional<State, number>
* ```
*
* @see {@link id} — start a composition chain
*/
compose<B>(this: Iso<S, A>, that: Iso<A, B>): Iso<S, B>
compose<B>(this: Lens<S, A>, that: Lens<A, B>): Lens<S, B>
compose<B>(this: Prism<S, A>, that: Prism<A, B>): Prism<S, B>
compose<B>(this: Optional<S, A>, that: Optional<A, B>): Optional<S, B>
/**
* Returns a function `(s: S) => S` that applies `f` to the focused value.
* If the optic cannot focus, the original `s` is returned unchanged.
*
* **Example** (Incrementing a nested field)
*
* ```ts
* import { Optic } from "effect"
*
* type S = { readonly a: { readonly b: number } }
* const _b = Optic.id<S>().key("a").key("b")
*
* const inc = _b.modify((n) => n + 1)
* console.log(inc({ a: { b: 1 } }))
* // Output: { a: { b: 2 } }
* ```
*/
modify(f: (a: A) => A): (s: S) => S
/**
* Focuses on a property of the current struct/tuple focus.
*
* **Details**
*
* - On a {@link Lens}, returns a Lens.
* - On an {@link Optional}, returns an Optional.
* - Does **not** work on union types (compile error).
*
* **Example** (Drilling into nested structs)
*
* ```ts
* import { Optic } from "effect"
*
* type S = { readonly a: { readonly b: number } }
* const _b = Optic.id<S>().key("a").key("b")
*
* console.log(_b.get({ a: { b: 42 } }))
* // Output: 42
* ```
*/
key<S, A extends object, Key extends keyof A>(
this: Lens<S, A>,
key: Key,
..._err: ForbidUnion<A, "cannot use `key` on a union type">
): Lens<S, A[Key]>
key<S, A extends object, Key extends keyof A>(
this: Optional<S, A>,
key: Key,
..._err: ForbidUnion<A, "cannot use `key` on a union type">
): Optional<S, A[Key]>
/**
* Focuses on a key where setting `undefined` **removes** the key from the
* struct (or splices the element from an array/tuple).
*
* **Details**
*
* - The focus type becomes `A[Key] | undefined`.
* - Does **not** work on union types (compile error).
*
* **Example** (Deleting an optional key)
*
* ```ts
* import { Optic } from "effect"
*
* type S = { readonly a?: number }
* const _a = Optic.id<S>().optionalKey("a")
*
* console.log(_a.replace(undefined, { a: 1 }))
* // Output: {}
*
* console.log(_a.replace(2, {}))
* // Output: { a: 2 }
* ```
*/
optionalKey<S, A extends object, Key extends keyof A>(
this: Lens<S, A>,
key: Key,
..._err: ForbidUnion<A, "cannot use `optionalKey` on a union type">
): Lens<S, A[Key] | undefined>
optionalKey<S, A extends object, Key extends keyof A>(
this: Optional<S, A>,
key: Key,
..._err: ForbidUnion<A, "cannot use `optionalKey` on a union type">
): Optional<S, A[Key] | undefined>
/**
* Adds one or more `Schema` validation checks to the optic chain.
* `getResult` fails when any check fails; `set` passes through unchanged.
*
* **Details**
*
* - On a {@link Prism}, returns a Prism.
* - On an {@link Optional}, returns an Optional.
*
* **Example** (Focusing only on positive numbers)
*
* ```ts
* import { Optic, Result, Schema } from "effect"
*
* const _pos = Optic.id<number>().check(Schema.isGreaterThan(0))
*
* console.log(Result.isSuccess(_pos.getResult(5)))
* // Output: true
*
* console.log(Result.isFailure(_pos.getResult(-1)))
* // Output: true
* ```
*
* @see {@link fromChecks} — standalone prism from checks
*/
check<S, A>(this: Prism<S, A>, ...checks: readonly [SchemaAST.Check<A>, ...Array<SchemaAST.Check<A>>]): Prism<S, A>
check<S, A>(
this: Optional<S, A>,
...checks: readonly [SchemaAST.Check<A>, ...Array<SchemaAST.Check<A>>]
): Optional<S, A>
/**
* Narrows the focus to a subtype `B` using a type guard.
*
* **Details**
*
* - On a {@link Prism}, returns a Prism.
* - On an {@link Optional}, returns an Optional.
* - Pass optional `annotations` to customize the error message.
*
* **Example** (Narrowing a union)
*
* ```ts
* import { Optic, Result } from "effect"
*
* type B = { readonly _tag: "b"; readonly b: number }
* type S = { readonly _tag: "a"; readonly a: string } | B
*
* const _b = Optic.id<S>().refine(
* (s: S): s is B => s._tag === "b",
* { expected: `"b" tag` }
* )
*
* console.log(Result.isSuccess(_b.getResult({ _tag: "b", b: 1 })))
* // Output: true
* ```
*
* @see `.tag()` — shorthand for narrowing by `_tag`
*/
refine<S, A, B extends A>(
this: Prism<S, A>,
refinement: (a: A) => a is B,
annotations?: Schema.Annotations.Filter
): Prism<S, B>
refine<S, A, B extends A>(
this: Optional<S, A>,
refinement: (a: A) => a is B,
annotations?: Schema.Annotations.Filter
): Optional<S, B>
/**
* Narrows the focus to the variant of a tagged union with the given
* `_tag` value.
*
* **Details**
*
* - On a {@link Prism}, returns a Prism.
* - On an {@link Optional}, returns an Optional.
* - Shorthand for `.refine(s => s._tag === tag)`.
*
* **Example** (Focusing a tagged variant)
*
* ```ts
* import { Optic, Result } from "effect"
*
* type Shape =
* | { readonly _tag: "Circle"; readonly radius: number }
* | { readonly _tag: "Rect"; readonly width: number }
*
* const _radius = Optic.id<Shape>().tag("Circle").key("radius")
*
* console.log(Result.isSuccess(_radius.getResult({ _tag: "Circle", radius: 5 })))
* // Output: true
*
* console.log(Result.isFailure(_radius.getResult({ _tag: "Rect", width: 10 })))
* // Output: true
* ```
*
* @see `.refine()` — for arbitrary type guards
*/
tag<S, A extends { readonly _tag: SchemaAST.LiteralValue }, Tag extends A["_tag"]>(
this: Prism<S, A>,
tag: Tag
): Prism<S, Extract<A, { readonly _tag: Tag }>>
tag<S, A extends { readonly _tag: SchemaAST.LiteralValue }, Tag extends A["_tag"]>(
this: Optional<S, A>,
tag: Tag
): Optional<S, Extract<A, { readonly _tag: Tag }>>
/**
* Focuses on a key only if it exists (`Object.hasOwn`). Both
* `getResult` and `replaceResult` fail when the key is absent.
*
* **Details**
*
* Unlike `.key()`, which always succeeds on the read side, `.at()` is
* useful for Records or arrays where the key/index may not be present.
*
* - Always returns an {@link Optional}.
* - Does **not** work on union types (compile error).
*
* **Example** (Accessing records safely)
*
* ```ts
* import { Optic, Result } from "effect"
*
* type Env = { [key: string]: number }
* const _x = Optic.id<Env>().at("x")
*
* console.log(Result.isSuccess(_x.getResult({ x: 1 })))
* // Output: true
*
* console.log(Result.isFailure(_x.getResult({ y: 2 })))
* // Output: true
* ```
*
* @see `.key()` — when the key is always present
*/
at<S, A extends object, Key extends keyof A>(
this: Optional<S, A>,
key: Key,
..._err: ForbidUnion<A, "cannot use `at` on a union type">
): Optional<S, A[Key]>
/**
* Focuses on a subset of keys of the current struct focus.
*
* **Details**
*
* - On a {@link Lens}, returns a Lens.
* - On an {@link Optional}, returns an Optional.
* - Does **not** work on union types (compile error).
*
* **Example** (Picking keys)
*
* ```ts
* import { Optic } from "effect"
*
* type S = { readonly a: string; readonly b: number; readonly c: boolean }
*
* const _ac = Optic.id<S>().pick(["a", "c"])
*
* console.log(_ac.get({ a: "hi", b: 1, c: true }))
* // Output: { a: "hi", c: true }
* ```
*
* @see `.omit()` — the inverse operation
*/
pick<S, A, Keys extends ReadonlyArray<keyof A>>(
this: Lens<S, A>,
keys: Keys,
..._err: ForbidUnion<A, "cannot use `pick` on a union type">
): Lens<S, Pick<A, Keys[number]>>
pick<S, A, Keys extends ReadonlyArray<keyof A>>(
this: Optional<S, A>,
keys: Keys,
..._err: ForbidUnion<A, "cannot use `pick` on a union type">
): Optional<S, Pick<A, Keys[number]>>
/**
* Focuses on all keys **except** the specified ones.
*
* **Details**
*
* - On a {@link Lens}, returns a Lens.
* - On an {@link Optional}, returns an Optional.
* - Does **not** work on union types (compile error).
*
* **Example** (Omitting keys)
*
* ```ts
* import { Optic } from "effect"
*
* type S = { readonly a: string; readonly b: number; readonly c: boolean }
*
* const _ac = Optic.id<S>().omit(["b"])
*
* console.log(_ac.get({ a: "hi", b: 1, c: true }))
* // Output: { a: "hi", c: true }
* ```
*
* @see `.pick()` — the inverse operation
*
* @since 4.0.0
*/
omit<S, A, Keys extends ReadonlyArray<keyof A>>(
this: Lens<S, A>,
keys: Keys,
..._err: ForbidUnion<A, "cannot use `omit` on a union type">
): Lens<S, Omit<A, Keys[number]>>
omit<S, A, Keys extends ReadonlyArray<keyof A>>(
this: Optional<S, A>,
keys: Keys,
..._err: ForbidUnion<A, "cannot use `omit` on a union type">
): Optional<S, Omit<A, Keys[number]>>
/**
* Filters out `undefined` from the focus, producing a {@link Prism}.
* `getResult` fails when the focus is `undefined`.
*
* **Example** (Filtering undefined values)
*
* ```ts
* import { Optic, Result } from "effect"
*
* const _defined = Optic.id<number | undefined>().notUndefined()
*
* console.log(Result.isSuccess(_defined.getResult(42)))
* // Output: true
*
* console.log(Result.isFailure(_defined.getResult(undefined)))
* // Output: true
* ```
*
* @since 4.0.0
*/
notUndefined(): Prism<S, Exclude<A, undefined>>
notUndefined(): Optional<S, Exclude<A, undefined>>
/**
* Focuses **all elements** of an array-like focus and optionally narrows
* to a subset using an element-level optic.
* Available only on {@link Traversal} (i.e. when `A` is
* `ReadonlyArray<Element>`). Returns a new Traversal focused on the
* selected elements.
*
* **Details**
*
* - **getResult** collects the values focused by `f(id<A>())` for each
* element. Non-focusable elements are skipped.
* - **replaceResult** expects exactly as many values as were collected by
* `getResult` and writes them back in order. Fails with a
* length-mismatch error if counts differ.
*
* **Example** (Incrementing liked posts)
*
* ```ts
* import { Optic, Schema } from "effect"
*
* type Post = { title: string; likes: number }
* type S = { user: { posts: ReadonlyArray<Post> } }
*
* const _likes = Optic.id<S>()
* .key("user")
* .key("posts")
* .forEach((post) => post.key("likes").check(Schema.isGreaterThan(0)))
*
* const addLike = _likes.modifyAll((n) => n + 1)
*
* console.log(
* addLike({
* user: { posts: [{ title: "a", likes: 0 }, { title: "b", likes: 1 }] }
* })
* )
* // Output: { user: { posts: [{ title: "a", likes: 0 }, { title: "b", likes: 2 }] } }
* ```
*
* @see {@link getAll} — extract all focused elements as an array
* @see `.modifyAll()` — apply a function to every focused element
*/
forEach<S, A, B>(this: Traversal<S, A>, f: (iso: Iso<A, A>) => Optional<A, B>): Traversal<S, B>
/**
* Applies a function to **every** element focused by the traversal.
*
* **Details**
*
* Available only on {@link Traversal}. Returns a function `(s: S) => S`.
* If the traversal cannot focus, the original `s` is returned unchanged.
*
* Unlike `.modify()`, which operates on the whole array, `modifyAll`
* maps `f` over each individual element.
*
* **Example** (Doubling all focused values)
*
* ```ts
* import { Optic, Schema } from "effect"
*
* type S = { readonly items: ReadonlyArray<number> }
*
* const _positive = Optic.id<S>()
* .key("items")
* .forEach((n) => n.check(Schema.isGreaterThan(0)))
*
* const doubled = _positive.modifyAll((n) => n * 2)
*
* console.log(doubled({ items: [1, -2, 3] }))
* // Output: { items: [2, -2, 6] }
* ```
*
* @see `.forEach()` — create a sub-traversal
* @see {@link getAll} — extract focused elements
*/
modifyAll<S, A>(this: Traversal<S, A>, f: (a: A) => A): (s: S) => S
}

Source

Since v4.0.0

Focuses on a part A of S that may not be present (e.g. a union variant or a validated subset).

When to use

Use when the focus is conditional — reading can fail (wrong variant, failed validation).

  • Building a new S from A does not require the original S.

Details

  • getResult(s) returns Result.Success<A> when the focus matches, or Result.Failure<string> with an error message.
  • set(a) always succeeds and returns a new S.
  • Extends Optional.
  • Composing two Prisms produces a Prism; composing a Prism with a Lens produces an Optional.

Example (Narrowing a tagged union)

import { Optic, Result } from "effect"
type Shape = { readonly _tag: "Circle"; readonly radius: number } | { readonly _tag: "Rect"; readonly width: number }
const _circle = Optic.id<Shape>().tag("Circle")
console.log(Result.isSuccess(_circle.getResult({ _tag: "Circle", radius: 5 })))
// Output: true
console.log(Result.isFailure(_circle.getResult({ _tag: "Rect", width: 10 })))
// Output: true

See

  • makePrism — constructor
  • fromChecks — build a Prism from schema checks
  • Lens — when reading always succeeds

Signature

export interface Prism<in out S, in out A> extends Optional<S, A> {
readonly set: (a: A) => S
}

Source

Since v4.0.0

Prism that focuses on the failure value of a Result.

When to use

Use when you have a Result<A, E> and want to read/update E only when it is a Failure.

Details

  • getResult fails when the result is a Success.
  • set(e) produces Result.fail(e).

Example (Accessing failure)

import { Optic, Result } from "effect"
const _err = Optic.id<Result.Result<number, string>>().compose(Optic.failure())
console.log(Result.isSuccess(_err.getResult(Result.fail("oops"))))
// Output: true
console.log(Result.isFailure(_err.getResult(Result.succeed(42))))
// Output: true

See

  • success — focuses on the success side
  • Prism — the type this function returns

Signature

declare const failure: <A, E>() => Prism<Result.Result<A, E>, E>

Source

Since v4.0.0

Prism that focuses on Option.None, exposing undefined.

When to use

Use when you want to match or construct None values within an optic chain.

Details

  • getResult succeeds with undefined when the option is None.
  • getResult fails when the option is Some.
  • set(undefined) produces Option.none().

Example (Matching None)

import { Optic, Option, Result } from "effect"
const _none = Optic.id<Option.Option<number>>().compose(Optic.none())
console.log(Result.isSuccess(_none.getResult(Option.none())))
// Output: true
console.log(Result.isFailure(_none.getResult(Option.some(1))))
// Output: true

See

  • some — focuses on Some instead
  • Prism — the type this function returns

Signature

declare const none: <A>() => Prism<Option.Option<A>, undefined>

Source

Since v4.0.0

Prism that focuses on the value inside Option.Some.

When to use

Use when you have an Option<A> and want to read/update the inner value only when it is Some.

Details

  • getResult fails with an error message when the option is None.
  • set(a) wraps a in Option.some(a).

Example (Accessing Some value)

import { Optic, Option, Result } from "effect"
const _some = Optic.id<Option.Option<number>>().compose(Optic.some())
console.log(Result.isSuccess(_some.getResult(Option.some(42))))
// Output: true
console.log(Result.isFailure(_some.getResult(Option.none())))
// Output: true
console.log(_some.set(10))
// Output: { _tag: "Some", value: 10 }

See

  • none — focuses on None instead
  • Prism — the type this function returns

Signature

declare const some: <A>() => Prism<Option.Option<A>, A>

Source

Since v4.0.0

Prism that focuses on the success value of a Result.

When to use

Use when you have a Result<A, E> and want to read/update A only when it is a Success.

Details

  • getResult fails when the result is a Failure.
  • set(a) produces Result.succeed(a).

Example (Accessing success)

import { Optic, Result } from "effect"
const _ok = Optic.id<Result.Result<number, string>>().compose(Optic.success())
console.log(Result.isSuccess(_ok.getResult(Result.succeed(42))))
// Output: true
console.log(Result.isFailure(_ok.getResult(Result.fail("err"))))
// Output: true

See

  • failure — focuses on the failure side
  • Prism — the type this function returns

Signature

declare const success: <A, E>() => Prism<Result.Result<A, E>, A>

Source

Since v4.0.0

An optic that focuses on zero or more elements of type A inside S.

When to use

Use when you want to read/update multiple elements at once (e.g. all items in an array, or a filtered subset).

Details

  • Technically Optional<S, ReadonlyArray<A>> — the focused value is an array of all matched elements.
  • Use .forEach() to add per-element sub-optics (filtering, drilling deeper).
  • Use .modifyAll(f) to map a function over every focused element.
  • Use getAll to extract all focused elements as a plain array.

Example (Traversing array elements with a filter)

import { Optic, Schema } from "effect"
type S = { readonly items: ReadonlyArray<number> }
const _positive = Optic.id<S>()
.key("items")
.forEach((n) => n.check(Schema.isGreaterThan(0)))
const getPositive = Optic.getAll(_positive)
console.log(getPositive({ items: [1, -2, 3] }))
// Output: [1, 3]

See

  • getAll — extract focused elements
  • Optional — the base type

Signature

export interface Traversal<in out S, in out A> extends Optional<S, ReadonlyArray<A>> {}

Source

Since v4.0.0

Returns a function that extracts all elements focused by a Traversal as a plain mutable array.

When to use

Use when you need the focused values as a simple Array<A> for further processing.

Details

  • Returns an empty array when the traversal cannot focus.
  • Always returns a fresh array (safe to mutate).

Example (Collecting positive numbers)

import { Optic, Schema } from "effect"
type S = { readonly values: ReadonlyArray<number> }
const _pos = Optic.id<S>()
.key("values")
.forEach((n) => n.check(Schema.isGreaterThan(0)))
const getPositive = Optic.getAll(_pos)
console.log(getPositive({ values: [3, -1, 5] }))
// Output: [3, 5]
console.log(getPositive({ values: [-1, -2] }))
// Output: []

See

  • Traversal — the optic type this operates on

Signature

declare const getAll: <S, A>(traversal: Traversal<S, A>) => (s: S) => Array<A>

Source

Since v4.0.0

Creates a Prism from one or more Schema validation checks.

When to use

Use when you want to narrow T to the subset that passes certain validation rules (e.g. positive integer).

  • You already have Schema.isGreaterThan, Schema.isInt, etc.

Details

  • getResult runs all checks; fails with a combined error message when any check fails.
  • set is identity — the value passes through unchanged.

Example (Creating a positive integer prism)

import { Optic, Result, Schema } from "effect"
const posInt = Optic.fromChecks<number>(Schema.isGreaterThan(0), Schema.isInt())
console.log(Result.isSuccess(posInt.getResult(3)))
// Output: true
console.log(Result.isFailure(posInt.getResult(-1)))
// Output: true

See

  • makePrism — constructor with custom getter/setter
  • Prism — the type this function returns

Signature

declare const fromChecks: <T>(checks_0: SchemaAST.Check<T>, ...checks: Array<SchemaAST.Check<T>>) => Prism<T, T>

Source

Since v4.0.0

Creates an Iso from a pair of conversion functions.

When to use

Use when you have two pure conversion functions that preserve all information between S and A.

Details

The returned optic can be composed with any other optic.

Example (Wrapping and unwrapping a branded type)

import { Optic } from "effect"
type Meters = { readonly value: number }
const meters = Optic.makeIso<Meters, number>(
(m) => m.value,
(n) => ({ value: n })
)
console.log(meters.get({ value: 100 }))
// Output: 100
console.log(meters.set(42))
// Output: { value: 42 }

See

  • Iso — the type this function returns
  • id — identity iso (no conversion)

Signature

declare const makeIso: <S, A>(get: (s: S) => A, set: (a: A) => S) => Iso<S, A>

Source

Since v4.0.0

Creates a Lens from a getter and a replacer.

When to use

Use when you can always extract A from S and produce a new S by substituting a new A.

Details

  • replace(a, s) should return a structurally new S with a in place of the old focus.

Example (Focusing on the first element of a pair)

import { Optic } from "effect"
const _first = Optic.makeLens<readonly [string, number], string>(
(pair) => pair[0],
(s, pair) => [s, pair[1]]
)
console.log(_first.get(["hello", 42]))
// Output: "hello"
console.log(_first.replace("world", ["hello", 42]))
// Output: ["world", 42]

See

  • Lens — the type this function returns
  • makeIso — when no original S is needed for set

Signature

declare const makeLens: <S, A>(get: (s: S) => A, replace: (a: A, s: S) => S) => Lens<S, A>

Source

Since v4.0.0

Creates an Optional from a fallible getter and a fallible setter.

When to use

Use when you need an optic for a focus that may be missing on read and may reject updates on write.

Details

  • getResult should return Result.fail(message) on mismatch.
  • set should return Result.fail(message) when the update cannot be applied.

Example (Accessing record keys safely)

import { Optic, Result } from "effect"
const atKey = (key: string) =>
Optic.makeOptional<Record<string, number>, number>(
(s) => (Object.hasOwn(s, key) ? Result.succeed(s[key]) : Result.fail(`Key "${key}" not found`)),
(a, s) => (Object.hasOwn(s, key) ? Result.succeed({ ...s, [key]: a }) : Result.fail(`Key "${key}" not found`))
)
console.log(Result.isSuccess(atKey("x").getResult({ x: 1 })))
// Output: true

See

  • Optional — the type this function returns
  • makeLens — when reading always succeeds
  • makePrism — when writing always succeeds

Signature

declare const makeOptional: <S, A>(
getResult: (s: S) => Result.Result<A, string>,
set: (a: A, s: S) => Result.Result<S, string>
) => Optional<S, A>

Source

Since v4.0.0

Creates a Prism from a fallible getter and an infallible setter.

When to use

Use when reading can fail (the part may not exist in S), but building S from A always succeeds.

Details

  • getResult should return Result.fail(message) on mismatch.

Example (Parsing a string to a number)

import { Optic, Result } from "effect"
const numeric = Optic.makePrism<string, number>((s) => {
const n = Number(s)
return Number.isNaN(n) ? Result.fail("not a number") : Result.succeed(n)
}, String)
console.log(Result.isSuccess(numeric.getResult("42")))
// Output: true
console.log(numeric.set(42))
// Output: "42"

See

  • Prism — the type this function returns
  • fromChecks — build from Schema checks instead

Signature

declare const makePrism: <S, A>(getResult: (s: S) => Result.Result<A, string>, set: (a: A) => S) => Prism<S, A>

Source

Since v4.0.0