<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>Applies a transformation to a schema's encoded type, creating a new schema where encoding/decoding
operate on S["Encoded"] rather than S["Type"].
Details
The decode getter maps S["Encoded"] → S["Encoded"] (applied during decoding),
and the encode getter maps S["Encoded"] → S["Encoded"] (applied during encoding).
Example (Upper-casing encoded strings)
import { Schema, SchemaGetter } from "effect"
const UpperFromLower = Schema.String.pipe(
Schema.encode({
decode: SchemaGetter.transform((s: string) => s.toLowerCase()),
encode: SchemaGetter.transform((s: string) => s.toUpperCase())
})
)export function function encode<
S extends Constraint,
RD = never,
RE = never
>(transformation: {
readonly decode: SchemaGetter.Getter<
S["Encoded"],
S["Encoded"],
RD
>
readonly encode: SchemaGetter.Getter<
S["Encoded"],
S["Encoded"],
RE
>
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
Applies a transformation to a schema's encoded type, creating a new schema where encoding/decoding
operate on S["Encoded"] rather than S["Type"].
Details
The decode getter maps S["Encoded"] → S["Encoded"] (applied during decoding),
and the encode getter maps S["Encoded"] → S["Encoded"] (applied during encoding).
Example (Upper-casing encoded strings)
import { Schema, SchemaGetter } from "effect"
const UpperFromLower = Schema.String.pipe(
Schema.encode({
decode: SchemaGetter.transform((s: string) => s.toLowerCase()),
encode: SchemaGetter.transform((s: string) => s.toUpperCase())
})
)
encode<function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S extends Constraint, function (type parameter) RD in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
RD = never, function (type parameter) RE in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<
S["Encoded"],
S["Encoded"],
RD
>
readonly encode: SchemaGetter.Getter<
S["Encoded"],
S["Encoded"],
RE
>
}
transformation: {
readonly decode: SchemaGetter.Getter<
S["Encoded"],
S["Encoded"],
RD
>
(property) decode: {
run: (input: Option.Option<E>, options: SchemaAST.ParseOptions) => Effect.Effect<Option.Option<T>, SchemaIssue.Issue, R>;
map: (f: (t: S['Encoded']) => T2) => SchemaGetter.Getter<T2, S['Encoded'], RD>;
compose: (other: SchemaGetter.Getter<T2, S['Encoded'], R2>) => SchemaGetter.Getter<T2, S['Encoded'], RD | R2>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
decode: import SchemaGetterSchemaGetter.class Getter<out T, in E, R = never>class Getter {
run: (input: Option.Option<E>, options: SchemaAST.ParseOptions) => Effect.Effect<Option.Option<T>, SchemaIssue.Issue, R>;
map: <T2>(f: (t: T) => T2) => Getter<T2, E, R>;
compose: <T2, R2>(other: Getter<T2, T, R2>) => Getter<T2, E, R | R2>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
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 wraps a function Option<E> -> Effect<Option<T>, Issue, R>. It
receives Option.None when the encoded key is absent, such as a missing
struct field, and returns Option.None to omit the value from the decoded
output. It fails with Issue on invalid input and may require Effect
services via R. .map(f) applies f to the decoded value inside Some
while leaving None unchanged. .compose(other) chains two getters by
feeding the output of this into other; passthrough getters on either side
are optimized away.
Example (Creating and composing getters)
import { SchemaGetter } from "effect"
const parseNumber = SchemaGetter.transform<number, string>((s) => Number(s))
const double = SchemaGetter.transform<number, number>((n) => n * 2)
const composed = parseNumber.compose(double)
// composed: Getter<number, string> — parses then doubles
Getter<function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S["Encoded"], function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S["Encoded"], function (type parameter) RD in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
RD>
readonly encode: SchemaGetter.Getter<
S["Encoded"],
S["Encoded"],
RE
>
(property) encode: {
run: (input: Option.Option<E>, options: SchemaAST.ParseOptions) => Effect.Effect<Option.Option<T>, SchemaIssue.Issue, R>;
map: (f: (t: S['Encoded']) => T2) => SchemaGetter.Getter<T2, S['Encoded'], RE>;
compose: (other: SchemaGetter.Getter<T2, S['Encoded'], R2>) => SchemaGetter.Getter<T2, S['Encoded'], RE | R2>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
encode: import SchemaGetterSchemaGetter.class Getter<out T, in E, R = never>class Getter {
run: (input: Option.Option<E>, options: SchemaAST.ParseOptions) => Effect.Effect<Option.Option<T>, SchemaIssue.Issue, R>;
map: <T2>(f: (t: T) => T2) => Getter<T2, E, R>;
compose: <T2, R2>(other: Getter<T2, T, R2>) => Getter<T2, E, R | R2>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
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 wraps a function Option<E> -> Effect<Option<T>, Issue, R>. It
receives Option.None when the encoded key is absent, such as a missing
struct field, and returns Option.None to omit the value from the decoded
output. It fails with Issue on invalid input and may require Effect
services via R. .map(f) applies f to the decoded value inside Some
while leaving None unchanged. .compose(other) chains two getters by
feeding the output of this into other; passthrough getters on either side
are optimized away.
Example (Creating and composing getters)
import { SchemaGetter } from "effect"
const parseNumber = SchemaGetter.transform<number, string>((s) => Number(s))
const double = SchemaGetter.transform<number, number>((n) => n * 2)
const composed = parseNumber.compose(double)
// composed: Getter<number, string> — parses then doubles
Getter<function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S["Encoded"], function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S["Encoded"], function (type parameter) RE in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
RE>
}) {
return (self: S extends Constraintself: function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S): interface decodeTo<To extends Constraint, From extends Constraint, RD = never, RE = never>Creates a schema that transforms from a source schema to a target schema.
When to use
Use when decoding should change the schema's decoded type or encoded shape,
with an optional custom bidirectional transformation.
Details
Call it with the target schema to and then pipe the source schema from
into the returned function. The resulting schema decodes from
From["Encoded"] to To["Type"] and encodes from To["Type"] back to
From["Encoded"].
When no transformation is provided, SchemaTransformation.passthrough() is
used, so From["Type"] must already be compatible with To["Encoded"].
The resulting schema combines decoding and encoding services from both
schemas and any custom transformation.
Gotchas
In a custom transformation, decode maps From["Type"] to To["Encoded"]
and is used on the encoding path, while encode maps To["Encoded"] to
From["Type"] and is used on the decoding path.
Example (Transforming strings to numbers with a schema transformation)
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))
}
)
)
const result = Schema.decodeUnknownSync(NumberFromString)("123")
// result: 123
Type-level representation returned by
decodeTo
.
decodeTo<function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S, interface toEncoded<S extends Constraint>Type-level representation returned by
toEncoded
.
Extracts the encoded-side schema: sets Type to equal the Encoded,
discarding the decoding transformation path.
toEncoded<function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S>, function (type parameter) RD in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
RD, function (type parameter) RE in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
RE> => {
return function decodeTo<S, toEncoded<S>, RD, RE>(to: S, transformation: {
readonly decode: SchemaGetter.Getter<NoInfer<S["Encoded"]>, NoInfer<S["Encoded"]>, RD>;
readonly encode: SchemaGetter.Getter<NoInfer<S["Encoded"]>, NoInfer<S["Encoded"]>, RE>;
}): (from: toEncoded<S>) => decodeTo<S, toEncoded<S>, RD, RE> (+1 overload)
Creates a schema that transforms from a source schema to a target schema.
When to use
Use when decoding should change the schema's decoded type or encoded shape,
with an optional custom bidirectional transformation.
Details
Call it with the target schema to and then pipe the source schema from
into the returned function. The resulting schema decodes from
From["Encoded"] to To["Type"] and encodes from To["Type"] back to
From["Encoded"].
When no transformation is provided, SchemaTransformation.passthrough() is
used, so From["Type"] must already be compatible with To["Encoded"].
The resulting schema combines decoding and encoding services from both
schemas and any custom transformation.
Gotchas
In a custom transformation, decode maps From["Type"] to To["Encoded"]
and is used on the encoding path, while encode maps To["Encoded"] to
From["Type"] and is used on the decoding path.
Example (Transforming strings to numbers with a schema transformation)
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))
}
)
)
const result = Schema.decodeUnknownSync(NumberFromString)("123")
// result: 123
decodeTo<function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S, interface toEncoded<S extends Constraint>Type-level representation returned by
toEncoded
.
Extracts the encoded-side schema: sets Type to equal the Encoded,
discarding the decoding transformation path.
toEncoded<function (type parameter) S in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
S>, function (type parameter) RD in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
RD, function (type parameter) RE in encode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>;
readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>;
}): (self: S) => decodeTo<S, toEncoded<S>, RD, RE>
RE>(self: S extends Constraintself, transformation: {
readonly decode: SchemaGetter.Getter<
S["Encoded"],
S["Encoded"],
RD
>
readonly encode: SchemaGetter.Getter<
S["Encoded"],
S["Encoded"],
RE
>
}
transformation)(const toEncoded: toEncodedLambda
;<S>(self: S) => toEncoded<S>
Type-level representation returned by
toEncoded
.
Extracts the encoded-side schema: sets Type to equal the Encoded,
discarding the decoding transformation path.
toEncoded(self: S extends Constraintself))
}
}