Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

SchemaGetter

Builds one-way conversions used by schemas.

A Getter<T, E, R> receives an optional encoded value and returns an optional decoded value. It can also report a schema issue or require Effect services. Schema transformations use getters to describe one direction of a conversion, for example decoding a field from input data. This module includes basic getters, validation helpers, pure and effectful conversions, and ready-made conversions for common string, number, binary, date, form, and URL-related values.

60 exports Since v4.0.0 Source

Combining

Since v4.0.0

Composes two getters by passing the output of the first to the second.

When to use

Use when a schema conversion requires multiple transformation steps.

Details

Composition forwards Option.none() to getters that handle optional values and skips getters that operate only on present values. Composing with passthrough returns the other getter unchanged. The function supports both compose(first, second) and first.pipe(compose(second)).

Signature

declare const compose: {
<T, T2, R2>(other: Getter<T2, T, R2>): <E, R>(self: Getter<T, E, R>) => Getter<T2, E, R2 | R>;
<T, E, R, T2, R2>(self: Getter<T, E, R>, other: Getter<T2, T, R2>): Getter<T2, E, R | R2>;
}

Example Parsing and normalizing a number

import { Effect, Option, SchemaGetter } from "effect"
const getter = SchemaGetter.compose(
SchemaGetter.transform<number, string>(Number),
SchemaGetter.transform((n) => Math.max(0, n))
)
Effect.runSync(SchemaGetter.run(getter, Option.some("-1"), {})) // => Option.some(0)

Joins a record of key-value pairs into a delimited string.

When to use

Use when you need a schema getter to serialize a present decoded record as a delimited key-value string.

Details

The getter is pure and never fails. It joins entries with separator (default ,) and joins each key and value with keyValueSeparator (default =).

See

Signature

declare function joinKeyValue<E extends Record<PropertyKey, string>>(options?: {
readonly keyValueSeparator?: string;
readonly separator?: string;
}): Getter<string, E>

Example Joining key-value records

import { Effect, Option, SchemaGetter } from "effect"
const join = SchemaGetter.joinKeyValue()
const result = Effect.runSync(SchemaGetter.run(join, Option.some({ a: "1", b: "2" }), {}))
result // => Option.some("a=1,b=2")

Constructors

Since v4.0.0

Creates a getter that always fails with the given issue.

When to use

Use when you need a schema getter that unconditionally rejects input.

  • Building custom validation getters that produce specific error types.

Details

  • Always fails with the Issue returned by f.
  • The failure function receives the original Option<E> input and the effective ParseOptions for error context.

See

  • forbidden for a convenience helper for Forbidden issues
  • checkEffect to fail conditionally based on input value

Signature

declare function fail<T, E>(f: (oe: Option<E>, options: ParseOptions) => Issue): Getter<T, E>

Example Defining an always-failing getter

import { Effect, Option, SchemaGetter, SchemaIssue } from "effect"
const rejectAll = SchemaGetter.fail<string, string>(
() => new SchemaIssue.InvalidValue({ message: "not allowed" })
)
const issue = await Effect.runPromise(
Effect.flip(SchemaGetter.run(rejectAll, Option.some("x"), {}))
)
issue._tag // => "InvalidValue"

Creates a getter that always fails with a Forbidden issue.

When to use

Use when you need a schema getter to disallow a field or direction (encode/decode) entirely.

  • You want a clear "forbidden" error message in schema validation output.

Details

  • Always fails with SchemaIssue.Forbidden.
  • The message function receives the Option<E> input for context.

See

  • fail to fail with a custom issue type

Signature

declare function forbidden<T, E>(message: (oe: Option<E>) => string): Getter<T, E>

Example Forbidding a decode direction

import { Effect, Option, SchemaGetter } from "effect"
const noEncode = SchemaGetter.forbidden<string, number>(
() => "encoding is not supported"
)
const issue = await Effect.runPromise(
Effect.flip(SchemaGetter.run(noEncode, Option.some(1), {}))
)
issue._tag // => "Forbidden"

Getter that always fails with a Forbidden issue indicating that encoding is unsupported.

When to use

Use as the encode side of a decode-only Schema transformation.

Details

Its Getter<never, unknown> type is assignable to every encoding getter because it accepts any input and never produces an output value.

See

  • forbidden for a forbidden getter with a custom message

Signature

declare const forbiddenEncoding: Getter<never, unknown>

Example Rejecting encoding

import { Effect, Option, SchemaGetter } from "effect"
const issue = await Effect.runPromise(
Effect.flip(SchemaGetter.run(SchemaGetter.forbiddenEncoding, Option.some("value"), {}))
)
issue._tag // => "Forbidden"

Builds a nested tree object from a list of bracket-path entries.

When to use

Use when you need a schema getter to parse FormData or URLSearchParams entries into structured objects.

  • You have flat key-value pairs with bracket-path keys that need nesting.

Details

  • A bracket path is a string like "user[address][city]" that describes nested object/array structure.
  • Interprets bracket paths and constructs the corresponding nested object.
  • Builds and returns a nested object from the input entries.
  • Supported syntax:
    • "foo" โ†’ object key "foo"
    • "foo[bar]" โ†’ nested { foo: { bar: ... } }
    • "foo[0]" โ†’ array index { foo: [value] }
    • "foo[]" โ†’ append to array foo
    • "" โ†’ real empty key
  • Numeric bracket segments become array indices only when they are valid JavaScript array-index strings; otherwise they remain object keys.
  • An indexed container becomes an array only when it has at most 20 holes (missing indices below its highest index). Otherwise it is returned as an object keyed by the index strings, so untrusted input such as a[4294967294] cannot produce huge sparse arrays.
  • Duplicate keys for the same path are merged into arrays.
  • If a structural path conflicts with a previous leaf or a different container type, the later structural path replaces the conflicting value.
  • The notation has no escaping for ., [ or ], so keys containing these delimiters cannot be round-tripped without changing their structure.

See

Signature

declare function makeTreeRecord<A>(bracketPathEntries: readonly Array<readonly [string, A]>): TreeRecord<A>

Example Building a tree from bracket paths

import { SchemaGetter } from "effect"
SchemaGetter.makeTreeRecord([
["user[name]", "Alice"],
["user[tags][]", "admin"],
["user[tags][]", "editor"]
]) // => { user: { name: "Alice", tags: ["admin", "editor"] } }

Returns the identity getter โ€” passes the value through unchanged.

When to use

Use when you need a schema getter for one side of a decodeTo pair, either encode or decode, to pass values through unchanged.

Details

  • Pure, no allocation (singleton instance).
  • Optimized away by compose โ€” composing with a passthrough is free.
  • The default overload requires T === E. Pass { strict: false } to opt out of the type constraint.

See

Signature

declare function passthrough<T, E>(options: {
readonly strict: false;
}): Getter<T, E>
declare function passthrough<T>(): Getter<T, T>

Example Passing through identity transformations

import { Schema, SchemaGetter } from "effect"
// No transformation needed โ€” types already match
const StringToString = Schema.String.pipe(
Schema.decodeTo(Schema.String, {
decode: SchemaGetter.passthrough(),
encode: SchemaGetter.passthrough()
})
)
Schema.decodeSync(StringToString)("hello") // => "hello"

Returns the identity getter, typed for when the encoded type E is a subtype of T.

When to use

Use when you need a schema getter that passes values through without { strict: false } for an encoded type that narrows the decoded type.

Details

  • Same singleton as passthrough โ€” no allocation, optimized in composition.

See

Signature

declare function passthroughSubtype<T, E>(): Getter<T, E>

Example Passing through subtypes

import { Effect, Option, SchemaGetter } from "effect"
// "hello" extends string, so E extends T
const g = SchemaGetter.passthroughSubtype<string, "hello">()
Effect.runSync(SchemaGetter.run(g, Option.some("hello"), {})) // => Option.some("hello")

Returns the identity getter typed for the relationship T extends E.

When to use

Use when you need a schema getter that passes values through when the decoded/output type is narrower than the encoded/input type.

Details

  • Same singleton as passthrough โ€” no allocation, optimized in composition.

See

Signature

declare function passthroughSupertype<T, E>(): Getter<T, E>

Example Passing through supertypes

import { Effect, Option, SchemaGetter } from "effect"
// string extends string, so this is valid
const g = SchemaGetter.passthroughSupertype<string, string>()
Effect.runSync(SchemaGetter.run(g, Option.some("hello"), {})) // => Option.some("hello")
Since v4.0.0

Creates a getter that always produces the given constant value, ignoring the input.

When to use

Use when you need a schema getter that always decodes a field to a fixed value.

Details

The getter is pure and always returns Option.some(t) regardless of whether the input is Some or None.

See

Signature

declare function succeed<T, E>(t: T): Getter<T, E>

Example Returning a constant getter

import { Effect, Option, SchemaGetter } from "effect"
const alwaysZero = SchemaGetter.succeed(0)
Effect.runSync(SchemaGetter.run(alwaysZero, Option.none(), {})) // => Option.some(0)

Converting

Since v4.0.0

Coerces a value to bigint using the global BigInt() constructor.

When to use

Use when you need a schema getter to convert a present string, number, or boolean value to bigint.

Details

  • Delegates to globalThis.BigInt.
  • Throws at runtime if the input cannot be converted (e.g. non-numeric string).

Signature

declare function BigInt<E extends string | number | bigint | boolean>(): Getter<bigint, E>

Example Coercing to a bigint

import { Effect, Option, SchemaGetter } from "effect"
const toBigInt = SchemaGetter.BigInt<string>()
Effect.runSync(SchemaGetter.run(toBigInt, Option.some("42"), {})) // => Option.some(42n)
Since v4.0.0

Coerces any value to a boolean using the global Boolean() constructor.

When to use

Use when you need a schema getter to coerce a present encoded value to a boolean with Boolean().

Details

The getter is pure, never fails, and delegates to globalThis.Boolean.

Signature

declare function Boolean<E>(): Getter<boolean, E>

Example Coercing to a boolean

import { Effect, Option, SchemaGetter } from "effect"
const toBool = SchemaGetter.Boolean<string>()
Effect.runSync(SchemaGetter.run(toBool, Option.some("true"), {})) // => Option.some(true)

Flattens a nested object into bracket-path entries, filtering leaf values by a type guard.

When to use

Use when you need a schema getter to serialize structured objects to flat key-value entries.

  • Building custom FormData or URLSearchParams encoders.

Details

  • Takes a nested object and produces flat [bracketPath, value] pairs suitable for FormData or URLSearchParams.
  • Returns a curried function: first call provides the leaf type guard, second call provides the object.
  • Recursively traverses objects and arrays.
  • If all elements of an array are leaves, encodes them as multiple entries with the same key (e.g. tags=a&tags=b). Otherwise uses indexed bracket paths (e.g. items[0], items[1]).
  • Non-leaf values that aren't objects or arrays are silently skipped.
  • Empty arrays and objects produce no entries, and path delimiters in property names are not escaped. The resulting format is therefore lossy.

See

Signature

declare function collectBracketPathEntries<A>(isLeaf: (value: unknown) => value is A): (input: object) => Array<[bracketPath: string, value: A]>

Example Flattening an object to bracket paths

import { Predicate, SchemaGetter } from "effect"
const collectStrings = SchemaGetter.collectBracketPathEntries(Predicate.isString)
const entries = collectStrings({ user: { name: "Alice", tags: ["admin", "editor"] } })
entries // => [["user[name]", "Alice"], ["user[tags]", "admin"], ["user[tags]", "editor"]]
Since v4.0.0

Coerces a value to a Date using new Date(input).

When to use

Use when you need a schema getter to coerce a present string, number, or existing date object into a new date object.

Details

  • Delegates to new globalThis.Date(input).
  • Does not validate the result โ€” may produce an invalid Date.

See

Signature

declare function Date<E extends string | number | Date>(): Getter<Date, E>

Example Coercing to a Date

import { Effect, Option, SchemaGetter } from "effect"
const toDate = SchemaGetter.Date<string>()
const result = Effect.runSync(SchemaGetter.run(toDate, Option.some("1970-01-01"), {}))
Option.map(result, (date) => date.toISOString()) // => Option.some("1970-01-01T00:00:00.000Z")

Parses a DateTime.Input value into a DateTime.Utc.

When to use

Use when you need a schema getter to decode a present encoded date/time value to a DateTime.Utc.

Details

  • Accepted input includes existing DateTime values, partial date/time parts, instant objects, zoned instant objects, JavaScript Date instances, epoch milliseconds, and date strings.
  • Converts successfully parsed values to UTC.
  • Fails with SchemaIssue.InvalidValue if the input cannot be parsed as a valid DateTime.

See

  • Date for a simpler coercion to Date (no validation)

Signature

declare function dateTimeUtcFromInput<E extends Input>(): Getter<Utc, E>

Example Parsing DateTime

import { DateTime, Effect, Option, SchemaGetter } from "effect"
const parseDate = SchemaGetter.dateTimeUtcFromInput<string>()
const result = await Effect.runPromise(
SchemaGetter.run(parseDate, Option.some("2024-01-01T00:00:00Z"), {})
)
Option.map(result, DateTime.toEpochMillis) // => Option.some(1704067200000)
Since v4.0.0

Coerces any value to a number using the global Number() constructor.

When to use

Use when you need a schema getter to coerce a present encoded value to a number with Number().

Details

The getter is pure, never fails, and delegates to globalThis.Number. It may produce NaN for non-numeric inputs.

See

Signature

declare function Number<E>(): Getter<number, E>

Example Coercing to a number

import { Effect, Option, SchemaGetter } from "effect"
const toNumber = SchemaGetter.Number<string>()
Effect.runSync(SchemaGetter.run(toNumber, Option.some("42"), {})) // => Option.some(42)
Since v4.0.0

Runs a getter directly.

Details

This is a convenience API for executing a getter outside a schema. When the getter belongs to a schema, use the corresponding SchemaParser API. The result is an Effect for every getter variant, including synchronous ones.

Signature

declare const run: {
<E>(input: Option<E>, options: ParseOptions): <T, R>(self: Getter<T, E, R>) => Effect<Option<T>, Issue, R>;
<T, E, R>(self: Getter<T, E, R>, input: Option<E>, options: ParseOptions): Effect<Option<T>, Issue, R>;
}

Example Running a getter

import { Effect, Option, SchemaGetter } from "effect"
const getter = SchemaGetter.transform<number, string>(Number)
const result = Effect.runSync(
SchemaGetter.run(getter, Option.some("42"), {})
)
result // => Option.some(42)
Since v4.0.0

Coerces any value to a string using the global String() constructor.

When to use

Use when you need a schema getter to coerce a present encoded value to a string with String().

Details

The getter is pure, never fails, and delegates to globalThis.String.

See

Signature

declare function String<E>(): Getter<string, E>

Example Coercing to a string

import { Effect, Option, SchemaGetter } from "effect"
const toString = SchemaGetter.String<number>()
Effect.runSync(SchemaGetter.run(toString, Option.some(42), {})) // => Option.some("42")

Decoding

Decodes a Base64 string to a Uint8Array.

Details

  • Fails with SchemaIssue.InvalidValue if the input is not valid Base64.

See

Signature

declare function decodeBase64<E extends string>(): Getter<Uint8Array<ArrayBufferLike>, E>

Example Decoding Base64 to bytes

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeBase64<string>()
const result = await Effect.runPromise(SchemaGetter.run(decode, Option.some("AQID"), {}))
Option.map(result, Array.from) // => Option.some([1, 2, 3])

Decodes a Base64 string to a UTF-8 string.

Details

  • Fails with SchemaIssue.InvalidValue if the input is not valid Base64.

See

Signature

declare function decodeBase64String<E extends string>(): Getter<string, E>

Example Decoding Base64 to string

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeBase64String<string>()
const result = await Effect.runPromise(SchemaGetter.run(decode, Option.some("aGVsbG8="), {}))
result // => Option.some("hello")

Decodes a URL-safe Base64 string to a Uint8Array.

Details

  • Fails with SchemaIssue.InvalidValue if the input is not valid Base64Url.

See

Signature

declare function decodeBase64Url<E extends string>(): Getter<Uint8Array<ArrayBufferLike>, E>

Example Decoding Base64Url to bytes

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeBase64Url<string>()
const result = await Effect.runPromise(SchemaGetter.run(decode, Option.some("-_8="), {}))
Option.map(result, Array.from) // => Option.some([251, 255])

Decodes a URL-safe Base64 string to a UTF-8 string.

Details

  • Fails with SchemaIssue.InvalidValue if the input is not valid Base64Url.

See

Signature

declare function decodeBase64UrlString<E extends string>(): Getter<string, E>

Example Decoding Base64Url to string

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeBase64UrlString<string>()
const result = await Effect.runPromise(SchemaGetter.run(decode, Option.some("aGVsbG8"), {}))
result // => Option.some("hello")

Decodes a FormData object into a nested tree structure using bracket-path notation.

When to use

Use when you need a schema getter to parse FormData from HTTP requests into structured objects.

Details

The getter is pure and never fails. It interprets bracket-path keys such as user[name] and items[0] to build nested objects or arrays, and each leaf value is a string or Blob.

See

Signature

declare function decodeFormData(): Getter<TreeRecord<string | Blob>, FormData>

Example Decoding FormData

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeFormData()
const formData = new FormData()
formData.append("user[name]", "Alice")
const result = Effect.runSync(SchemaGetter.run(decode, Option.some(formData), {}))
result // => Option.some({ user: { name: "Alice" } })

Decodes a hexadecimal string to a Uint8Array.

Details

  • Fails with SchemaIssue.InvalidValue if the input is not valid hex.

See

Signature

declare function decodeHex<E extends string>(): Getter<Uint8Array<ArrayBufferLike>, E>

Example Decoding hex to bytes

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeHex<string>()
const result = await Effect.runPromise(SchemaGetter.run(decode, Option.some("010203"), {}))
Option.map(result, Array.from) // => Option.some([1, 2, 3])

Decodes a hexadecimal string to a UTF-8 string.

Details

  • Fails with SchemaIssue.InvalidValue if the input is not valid hex.

See

Signature

declare function decodeHexString<E extends string>(): Getter<string, E>

Example Decoding hex to string

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeHexString<string>()
const result = await Effect.runPromise(SchemaGetter.run(decode, Option.some("68656c6c6f"), {}))
result // => Option.some("hello")

Decodes a URI component encoded string using decodeURIComponent.

Details

  • Fails with SchemaIssue.InvalidValue if the input contains malformed percent-encoding sequences.

See

Signature

declare function decodeUriComponent<E extends string>(): Getter<string, E>

Example Decoding a URI component

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeUriComponent<string>()
const result = await Effect.runPromise(SchemaGetter.run(decode, Option.some("hello%20world"), {}))
result // => Option.some("hello world")

Decodes a URLSearchParams object into a nested tree structure using bracket-path notation.

When to use

Use when you need a schema getter to parse query parameters from URLs into structured objects.

Details

The getter is pure and never fails. It interprets bracket-path keys such as user[name] and items[0] to build nested objects or arrays, and each leaf value is a string.

See

Signature

declare function decodeURLSearchParams(): Getter<TreeRecord<string>, URLSearchParams>

Example Decoding URLSearchParams

import { Effect, Option, SchemaGetter } from "effect"
const decode = SchemaGetter.decodeURLSearchParams()
const params = new URLSearchParams("user[name]=Alice")
const result = Effect.runSync(SchemaGetter.run(decode, Option.some(params), {}))
result // => Option.some({ user: { name: "Alice" } })

Parses a JSON string into a value.

When to use

Use when you need a schema getter to parse a present encoded JSON string during decoding.

Details

  • Skips None inputs.
  • Without reviver: returns Schema.MutableJson (typed JSON).
  • With reviver: returns unknown (reviver may produce arbitrary values).
  • On parse failure, fails with SchemaIssue.InvalidValue whose expected annotation is "a valid JSON string". Its default message includes the reported input when reportInput is enabled.

See

Signature

declare function parseJson<E extends string>(): Getter<MutableJson, E>
declare function parseJson<E extends string>(options: ParseJsonOptions): Getter<unknown, E>

Example Parsing JSON

import { Effect, Option, SchemaGetter } from "effect"
const parse = SchemaGetter.parseJson<string>()
const result = await Effect.runPromise(SchemaGetter.run(parse, Option.some("{\"a\":1}"), {}))
result // => Option.some({ a: 1 })

Encoding

Encodes a Uint8Array or string to a Base64 string.

Details

The getter is pure and never fails.

See

Signature

declare function encodeBase64<E extends string | Uint8Array<ArrayBufferLike>>(): Getter<string, E>

Example Encoding to Base64

import { Effect, Option, SchemaGetter } from "effect"
const encode = SchemaGetter.encodeBase64<Uint8Array>()
const result = Effect.runSync(SchemaGetter.run(encode, Option.some(new Uint8Array([1, 2, 3])), {}))
result // => Option.some("AQID")

Encodes a Uint8Array or string to a URL-safe Base64 string.

Details

The getter is pure and never fails.

See

Signature

declare function encodeBase64Url<E extends string | Uint8Array<ArrayBufferLike>>(): Getter<string, E>

Example Encoding to Base64Url

import { Effect, Option, SchemaGetter } from "effect"
const encode = SchemaGetter.encodeBase64Url<Uint8Array>()
const result = Effect.runSync(SchemaGetter.run(encode, Option.some(new Uint8Array([251, 255])), {}))
result // => Option.some("-_8")

Encodes a nested object into a FormData instance using bracket-path notation.

When to use

Use when you need a schema getter to serialize structured data to FormData for HTTP requests.

Details

The getter is pure and never fails. It flattens nested objects or arrays into bracket-path keys such as user[name] and items[0]. Non-object inputs produce an empty FormData.

See

Signature

declare function encodeFormData(): Getter<FormData, unknown>

Example Encoding to FormData

import { Effect, Option, SchemaGetter } from "effect"
const encode = SchemaGetter.encodeFormData()
const result = Effect.runSync(SchemaGetter.run(encode, Option.some({ name: "Alice" }), {}))
Option.map(result, (formData) => formData.get("name")) // => Option.some("Alice")

Encodes a Uint8Array or string to a hexadecimal string.

Details

The getter is pure and never fails.

See

Signature

declare function encodeHex<E extends string | Uint8Array<ArrayBufferLike>>(): Getter<string, E>

Example Encoding to hex

import { Effect, Option, SchemaGetter } from "effect"
const encode = SchemaGetter.encodeHex<Uint8Array>()
const result = Effect.runSync(SchemaGetter.run(encode, Option.some(new Uint8Array([1, 2, 3])), {}))
result // => Option.some("010203")

Encodes a present string using encodeURIComponent.

Details

  • Skips None inputs.
  • May throw a URIError for malformed surrogate pairs; this exception is not converted into an Issue.

See

Signature

declare function encodeUriComponent<E extends string>(): Getter<string, E>

Example Encoding a URI component

import { Effect, Option, SchemaGetter } from "effect"
const encode = SchemaGetter.encodeUriComponent<string>()
const result = Effect.runSync(SchemaGetter.run(encode, Option.some("hello world"), {}))
result // => Option.some("hello%20world")

Encodes a nested object into a URLSearchParams instance using bracket-path notation.

When to use

Use when you need a schema getter to serialize structured data to query parameters for URLs.

Details

The getter is pure and never fails. It flattens nested objects or arrays into bracket-path keys. Non-object inputs produce an empty URLSearchParams.

See

Signature

declare function encodeURLSearchParams(): Getter<URLSearchParams, unknown>

Example Encoding to URLSearchParams

import { Effect, Option, SchemaGetter } from "effect"
const encode = SchemaGetter.encodeURLSearchParams()
const result = Effect.runSync(SchemaGetter.run(encode, Option.some({ name: "Alice" }), {}))
Option.map(result, (params) => params.toString()) // => Option.some("name=Alice")

Stringifies a present value using JSON.stringify.

When to use

Use when you need a schema getter to serialize a present decoded value to JSON text during encoding.

Details

  • Skips None inputs.
  • If JSON.stringify throws or returns undefined, fails with SchemaIssue.InvalidValue.
  • Supports optional replacer and space options, matching JSON.stringify.

See

Signature

declare function stringifyJson(options?: StringifyJsonOptions): Getter<string, unknown>

Example Stringifying JSON

import { Effect, Option, SchemaGetter } from "effect"
const stringify = SchemaGetter.stringifyJson()
const result = await Effect.runPromise(SchemaGetter.run(stringify, Option.some({ a: 1 }), {}))
result // => Option.some("{\"a\":1}")

Filtering

Since v4.0.0

Creates a getter that always returns None, effectively omitting the value from output.

When to use

Use when you need a schema getter to exclude a field during decoding or encoding.

Details

  • Always returns Option.None regardless of input.
  • Never fails.

See

Signature

declare function omit<T>(): Getter<never, T>

Example Omitting a field during encoding

import { Effect, Option, SchemaGetter } from "effect"
const omitField = SchemaGetter.omit<string>()
Effect.runSync(SchemaGetter.run(omitField, Option.some("hidden"), {})) // => Option.none()

Mapping

Since v4.0.0

Maps the output of a getter while preserving missing values.

When to use

Use to add a synchronous transformation after an existing getter.

Details

The mapping function runs only for Option.some. The function supports both map(self, f) and self.pipe(map(f)).

Signature

declare const map: {
<T, T2>(f: (value: T) => T2): <E, R>(self: Getter<T, E, R>) => Getter<T2, E, R>;
<T, E, R, T2>(self: Getter<T, E, R>, f: (value: T) => T2): Getter<T2, E, R>;
}

Example Mapping a getter result

import { Effect, Option, SchemaGetter } from "effect"
const getter = SchemaGetter.transform<number, string>(Number).pipe(
SchemaGetter.map((n) => n * 2)
)
Effect.runSync(SchemaGetter.run(getter, Option.some("21"), {})) // => Option.some(42)

Models

Since v4.0.0

Represents a composable transformation from an encoded type E to a decoded type T.

When to use

Use when you need a schema getter to build and compose custom transformations for Schema.decodeTo or Schema.decode.

Details

A getter receives an Option<E> and produces an Option<T>. Option.none() represents a missing struct field and can also omit a field from the output. A getter may fail with a schema issue or require services through R. The tagged representation distinguishes synchronous transformations from transformations that return an Effect, allowing schema parsers to select the corresponding execution path when they are built. Getter values expose pipe; use the standalone map, compose, and run functions to operate on them.

See

Signature

type Getter<T, E, R = never> = Passthrough | Transform<T, E> | TransformOptional<T, E> | TransformEffect<T, E, R> | TransformOptionalEffect<T, E, R>

Example Creating and composing getters

import { Effect, Option, SchemaGetter } from "effect"
const parseNumber = SchemaGetter.transform<number, string>((s) => Number(s))
const double = SchemaGetter.transform<number, number>((n) => n * 2)
const composed = SchemaGetter.compose(parseNumber, double)
Effect.runSync(SchemaGetter.run(composed, Option.some("21"), {})) // => Option.some(42)

Passthrough

interface
Since v4.0.0

A transformation that returns its input unchanged.

Signature

interface Passthrough extends Pipeable {
readonly _tag: "Passthrough";
}

Transform

interface
Since v4.0.0

A synchronous transformation of present values.

Signature

interface Transform<out T, in E> extends Pipeable {
readonly _tag: "Transform";
readonly transform: (input: E) => T;
}
Since v4.0.0

An effectful transformation of present values.

Signature

interface TransformEffect<out T, in E, R> extends Pipeable {
readonly _tag: "TransformEffect";
readonly transform: (input: E, options: ParseOptions) => Effect<T, Issue, R>;
}
Since v4.0.0

A synchronous transformation of optional values.

Signature

interface TransformOptional<out T, in E> extends Pipeable {
readonly _tag: "TransformOptional";
readonly transform: (input: Option<E>) => Option<T>;
}
Since v4.0.0

An effectful transformation of optional values.

Signature

interface TransformOptionalEffect<out T, in E, R> extends Pipeable {
readonly _tag: "TransformOptionalEffect";
readonly transform: (input: Option<E>, options: ParseOptions) => Effect<Option<T>, Issue, R>;
}

Splitting

Since v4.0.0

Splits a string into an array of strings by a separator.

When to use

Use when you need a schema getter to split a present encoded string containing a delimited list, such as CSV values.

Details

The getter is pure and never fails. It splits by separator (default ,). An empty string produces an empty array, not [""].

See

Signature

declare function split<E extends string>(options?: {
readonly separator?: string;
}): Getter<readonly Array<string>, E>

Example Splitting a comma-separated string

import { Effect, Option, SchemaGetter } from "effect"
const splitComma = SchemaGetter.split<string>()
const result = Effect.runSync(SchemaGetter.run(splitComma, Option.some("a,b,c"), {}))
result // => Option.some(["a", "b", "c"])

Parses a string into a record of key-value pairs.

When to use

Use when you need a schema getter to parse a present encoded string that contains delimited key-value pairs (e.g. "a=1,b=2").

Details

The getter is pure and never fails. It splits the string by separator (default ,) and then each pair at the first keyValueSeparator (default =), preserving the rest of the value. An empty keyValueSeparator uses the first two characters as the key and value. Pairs missing a key or value are skipped.

See

Signature

declare function splitKeyValue<E extends string>(options?: {
readonly keyValueSeparator?: string;
readonly separator?: string;
}): Getter<Record<string, string>, E>

Example Parsing a key-value string

import { Effect, Option, SchemaGetter } from "effect"
const parse = SchemaGetter.splitKeyValue<string>()
const result = Effect.runSync(SchemaGetter.run(parse, Option.some("a=1,b=2"), {}))
result // => Option.some({ a: "1", b: "2" })

Transforming

Converts a camelCase string to snake_case.

Details

  • Pure, delegates to String.camelToSnake.

See

Signature

declare function camelToSnake<E extends string>(): Getter<string, E>

Example Converting camel case to snake case

import { Effect, Option, SchemaGetter } from "effect"
const toSnake = SchemaGetter.camelToSnake<string>()
Effect.runSync(SchemaGetter.run(toSnake, Option.some("userName"), {})) // => Option.some("user_name")

Capitalizes the first character of a string.

Details

  • Pure, delegates to String.capitalize.

Signature

declare function capitalize<E extends string>(): Getter<string, E>

Example Capitalizing a string

import { Effect, Option, SchemaGetter } from "effect"
const cap = SchemaGetter.capitalize<string>()
Effect.runSync(SchemaGetter.run(cap, Option.some("hello"), {})) // => Option.some("Hello")

Converts a snake_case string to camelCase.

Details

  • Pure, delegates to String.snakeToCamel.

See

Signature

declare function snakeToCamel<E extends string>(): Getter<string, E>

Example Converting snake case to camel case

import { Effect, Option, SchemaGetter } from "effect"
const toCamel = SchemaGetter.snakeToCamel<string>()
Effect.runSync(SchemaGetter.run(toCamel, Option.some("user_name"), {})) // => Option.some("userName")

Converts a string to lowercase.

Details

  • Pure, delegates to String.toLowerCase.

See

Signature

declare function toLowerCase<E extends string>(): Getter<string, E>

Example Converting to lowercase

import { Effect, Option, SchemaGetter } from "effect"
const lower = SchemaGetter.toLowerCase<string>()
Effect.runSync(SchemaGetter.run(lower, Option.some("HELLO"), {})) // => Option.some("hello")

Converts a string to uppercase.

Details

  • Pure, delegates to String.toUpperCase.

See

Signature

declare function toUpperCase<E extends string>(): Getter<string, E>

Example Converting to uppercase

import { Effect, Option, SchemaGetter } from "effect"
const upper = SchemaGetter.toUpperCase<string>()
Effect.runSync(SchemaGetter.run(upper, Option.some("hello"), {})) // => Option.some("HELLO")

Creates a getter that applies a pure function to present values.

When to use

Use when you need a schema getter for a pure, infallible transformation between types.

  • Building encode/decode pairs for Schema.decodeTo.

Details

  • This is the most commonly used constructor.
  • Transforms Some(e) to Some(f(e)) and leaves None unchanged.
  • Skips None inputs โ€” only called when a value is present.
  • Never fails.

See

Signature

declare function transform<T, E>(f: (e: E) => T): Getter<T, E>

Example Transforming strings to numbers

import { Schema, SchemaGetter } from "effect"
const NumberFromString = Schema.String.pipe(
Schema.decodeTo(Schema.Number, {
decode: SchemaGetter.transform((s) => Number(s)),
encode: SchemaGetter.transform((n) => String(n))
})
)
Schema.decodeSync(NumberFromString)("42") // => 42

Creates a getter that applies an effectful transformation to present values.

When to use

Use when you need a schema getter for a transformation that may fail, require Effect services, or run asynchronously.

Details

  • Skips None inputs โ€” only called when a value is present.
  • On success, wraps the result in Some.
  • On failure, propagates the Issue.

See

Signature

declare function transformEffect<T, E, R = never>(f: (e: E, options: ParseOptions) => Effect<T, Issue, R>): Getter<T, E, R>

Example Parsing with failure

import { Effect, Option, SchemaGetter, SchemaIssue } from "effect"
const safeParseInt = SchemaGetter.transformEffect<number, string>(
(s, options) => {
const n = parseInt(s, 10)
return isNaN(n)
? Effect.fail(new SchemaIssue.InvalidValue({ message: "not an integer" }, s, options))
: Effect.succeed(n)
}
)
await Effect.runPromise(SchemaGetter.run(safeParseInt, Option.some("42"), {})) // => Option.some(42)

Creates a getter that transforms the full Option โ€” both present and absent values.

When to use

Use when you need a schema getter to handle both Some and None cases.

Details

The getter is pure and never fails. It receives the full Option<E> and must return Option<T>, so it can turn a present value into absent or an absent value into present.

See

  • transform when you only need to transform present values
  • omit when you always want None

Signature

declare function transformOptional<T, E>(f: (oe: Option<E>) => Option<T>): Getter<T, E>

Example Filtering out empty strings

import { Effect, Option, SchemaGetter } from "effect"
const skipEmpty = SchemaGetter.transformOptional<string, string>((o) =>
Option.filter(o, (s) => s.length > 0)
)
Effect.runSync(SchemaGetter.run(skipEmpty, Option.some(""), {})) // => Option.none()

Creates a getter that effectfully transforms the full Option.

Signature

declare function transformOptionalEffect<T, E, R = never>(f: (input: Option<E>, options: ParseOptions) => Effect<Option<T>, Issue, R>): Getter<T, E, R>
Since v4.0.0

Strips whitespace from both ends of a string.

Details

  • Pure, delegates to String.trim.

Signature

declare function trim<E extends string>(): Getter<string, E>

Example Trimming whitespace

import { Effect, Option, SchemaGetter } from "effect"
const trimmed = SchemaGetter.trim<string>()
Effect.runSync(SchemaGetter.run(trimmed, Option.some(" hello "), {})) // => Option.some("hello")

Uncapitalizes the first character of a string.

Details

  • Pure, delegates to String.uncapitalize.

Signature

declare function uncapitalize<E extends string>(): Getter<string, E>

Example Uncapitalizing a string

import { Effect, Option, SchemaGetter } from "effect"
const uncap = SchemaGetter.uncapitalize<string>()
Effect.runSync(SchemaGetter.run(uncap, Option.some("Hello"), {})) // => Option.some("hello")

Creates a getter that replaces undefined values with a default.

When to use

Use when you need a schema getter to provide a fallback for a field that may be undefined in the encoded input.

Details

  • If the input is Some(undefined) or None, produces Some(T).
  • If the input is Some(value) where value is not undefined, passes it through.
  • defaultValue is an Effect that will be executed each time a default is needed.

See

Signature

declare function withDefault<T, R = never>(defaultValue: Effect<T, Issue, R>): Getter<T, T | undefined, R>

Example Providing a default value for an optional field

import { Effect, Option, SchemaGetter } from "effect"
const withZero = SchemaGetter.withDefault(Effect.succeed(0))
await Effect.runPromise(SchemaGetter.run(withZero, Option.some(undefined), {})) // => Option.some(0)

Utility Types

Since v4.0.0

Replacer function or property allowlist accepted by JSON.stringify.

Signature

type JsonReplacer = (this: any, key: string, value: any) => any | Array<string | number> | null

Validation

Creates a getter that validates a value using an effectful check function.

When to use

Use when you need a schema getter to validate a decoded value (e.g. check a constraint or call an external service).

  • The validation may be asynchronous or require Effect services.

Details

  • Only runs when input is Some โ€” None passes through.
  • The check function returns a validation result:
    • undefined or true โ€” value is valid, passes through.
    • false or a string โ€” value is invalid, fails with an Issue.
    • An Issue object โ€” fails with that issue directly.
    • { path, issue } โ€” fails with a nested path issue (issue may be a message string or a full SchemaIssue.Issue).
  • Does not transform the value โ€” input and output types are the same.

See

  • transform when you need to change the value, not just validate
  • fail for unconditional failure

Signature

declare function checkEffect<T, R = never>(f: (input: T, options: ParseOptions) => Effect<boolean | FilterIssue | undefined, never, R>): Getter<T, T, R>

Example Validating effectfully

import { Effect, Option, SchemaGetter } from "effect"
const nonNegative = SchemaGetter.checkEffect<number>((n) =>
Effect.succeed(n >= 0 ? undefined : "must be non-negative")
)
await Effect.runPromise(SchemaGetter.run(nonNegative, Option.some(1), {})) // => Option.some(1)
Since v4.0.0

Creates a getter that fails with MissingKey if the input is absent (Option.None).

When to use

Use when you need a schema getter to require a struct field in the encoded input and report a missing key error when it is absent.

Details

  • When input is None, fails with SchemaIssue.MissingKey.
  • When input is Some, passes it through unchanged.
  • Optional annotations customize the error message for the missing key.

See

  • withDefault to substitute a default for undefined values

Signature

declare function required<T, E = T>(annotations?: Key<T>): Getter<T, E>

Example Defining a required struct field

import { Effect, Option, SchemaGetter } from "effect"
const mustExist = SchemaGetter.required<string>()
const issue = await Effect.runPromise(
Effect.flip(SchemaGetter.run(mustExist, Option.none(), {}))
)
issue._tag // => "MissingKey"