<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>
}): (self: S) => decodeTo<toType<S>, S, RD, RE>Applies a transformation to a schema, creating a new schema with the same type but transformed encoding/decoding.
When to use
Use when the decoded type stays the same and the transformation only normalizes values during encoding and decoding.
Details
Call it with a transformation object and then pipe a schema into the returned
function. The resulting schema keeps the same Type and Encoded types as
the source schema, while applying the transformation during both decoding and
encoding.
Internally this uses toType(self) as the target schema and combines service
requirements from the source schema and the transformation.
Gotchas
Use decodeTo instead when the transformation should change the
decoded type. For this helper, both transformation getters operate on
S["Type"] values.
Example (Trimming string values during encoding/decoding)
import { Schema, SchemaGetter } from "effect"
const Trimmed = Schema.String.pipe(
Schema.decode({
decode: SchemaGetter.transform((s) => s.trim()),
encode: SchemaGetter.transform((s) => s.trim())
})
)
const result = Schema.decodeUnknownSync(Trimmed)(" hello ")
// result: "hello"export function function decode<
S extends Constraint,
RD = never,
RE = never
>(transformation: {
readonly decode: SchemaGetter.Getter<
S["Type"],
S["Type"],
RD
>
readonly encode: SchemaGetter.Getter<
S["Type"],
S["Type"],
RE
>
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
Applies a transformation to a schema, creating a new schema with the same type but transformed encoding/decoding.
When to use
Use when the decoded type stays the same and the transformation only
normalizes values during encoding and decoding.
Details
Call it with a transformation object and then pipe a schema into the returned
function. The resulting schema keeps the same Type and Encoded types as
the source schema, while applying the transformation during both decoding and
encoding.
Internally this uses toType(self) as the target schema and combines service
requirements from the source schema and the transformation.
Gotchas
Use
decodeTo
instead when the transformation should change the
decoded type. For this helper, both transformation getters operate on
S["Type"] values.
Example (Trimming string values during encoding/decoding)
import { Schema, SchemaGetter } from "effect"
const Trimmed = Schema.String.pipe(
Schema.decode({
decode: SchemaGetter.transform((s) => s.trim()),
encode: SchemaGetter.transform((s) => s.trim())
})
)
const result = Schema.decodeUnknownSync(Trimmed)(" hello ")
// result: "hello"
decode<function (type parameter) S in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S extends Constraint, function (type parameter) RD in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
RD = never, function (type parameter) RE in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<
S["Type"],
S["Type"],
RD
>
readonly encode: SchemaGetter.Getter<
S["Type"],
S["Type"],
RE
>
}
transformation: {
readonly decode: SchemaGetter.Getter<
S["Type"],
S["Type"],
RD
>
(property) decode: {
run: (input: Option.Option<E>, options: SchemaAST.ParseOptions) => Effect.Effect<Option.Option<T>, SchemaIssue.Issue, R>;
map: (f: (t: S['Type']) => T2) => SchemaGetter.Getter<T2, S['Type'], RD>;
compose: (other: SchemaGetter.Getter<T2, S['Type'], R2>) => SchemaGetter.Getter<T2, S['Type'], 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 decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S["Type"], function (type parameter) S in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S["Type"], function (type parameter) RD in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
RD>
readonly encode: SchemaGetter.Getter<
S["Type"],
S["Type"],
RE
>
(property) encode: {
run: (input: Option.Option<E>, options: SchemaAST.ParseOptions) => Effect.Effect<Option.Option<T>, SchemaIssue.Issue, R>;
map: (f: (t: S['Type']) => T2) => SchemaGetter.Getter<T2, S['Type'], RE>;
compose: (other: SchemaGetter.Getter<T2, S['Type'], R2>) => SchemaGetter.Getter<T2, S['Type'], 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 decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S["Type"], function (type parameter) S in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S["Type"], function (type parameter) RE in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
RE>
}) {
return (self: S extends Constraintself: function (type parameter) S in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, 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<interface toType<S extends Constraint>Type-level representation returned by
toType
.
Extracts the type-side schema: sets Encoded to equal the decoded Type,
discarding the encoding transformation path.
toType<function (type parameter) S in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S>, function (type parameter) S in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S, function (type parameter) RD in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
RD, function (type parameter) RE in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
RE> => {
return function decodeTo<toType<S>, S, RD, RE>(to: toType<S>, transformation: {
readonly decode: SchemaGetter.Getter<NoInfer<S["Type"]>, NoInfer<S["Type"]>, RD>;
readonly encode: SchemaGetter.Getter<NoInfer<S["Type"]>, NoInfer<S["Type"]>, RE>;
}): (from: S) => decodeTo<toType<S>, 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<interface toType<S extends Constraint>Type-level representation returned by
toType
.
Extracts the type-side schema: sets Encoded to equal the decoded Type,
discarding the encoding transformation path.
toType<function (type parameter) S in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S>, function (type parameter) S in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
S, function (type parameter) RD in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
RD, function (type parameter) RE in decode<S extends Constraint, RD = never, RE = never>(transformation: {
readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>;
readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>;
}): (self: S) => decodeTo<toType<S>, S, RD, RE>
RE>(const toType: toTypeLambda
;<S>(self: S) => toType<S>
Type-level representation returned by
toType
.
Extracts the type-side schema: sets Encoded to equal the decoded Type,
discarding the encoding transformation path.
toType(self: S extends Constraintself), transformation: {
readonly decode: SchemaGetter.Getter<
S["Type"],
S["Type"],
RD
>
readonly encode: SchemaGetter.Getter<
S["Type"],
S["Type"],
RE
>
}
transformation)(self: S extends Constraintself)
}
}