Skip to content

SchemaTransformation

Builds two-way conversions used by schemas.

A Transformation<T, E> describes how to decode an encoded value into a decoded value and how to encode it back again. Schema APIs use transformations to connect two representations, such as a string and a number, a JSON value and a richer TypeScript value, or a form field and an application value. This module includes transformation and middleware types, constructors for pure or effectful conversions, and common conversions used by the Schema module.

44 exports Added in v3.10.0 Source

Constructors

make

Added in v3.10.0 Source

Constructs a Transformation from an object with decode and encode Getters. If the input is already a Transformation, returns it as-is.

When to use

Use when you already have schema getter instances and want to pair them into a schema transformation. - You want idempotent wrapping (won't double-wrap).

Details

- Returns the input unchanged if it is already a Transformation.

See

Signature

declare function make<T, E, RD = never, RE = never>(options: {
  readonly decode: Getter<T, E, RD>;
  readonly encode: Getter<E, T, RE>;
}): Transformation<T, E, RD, RE>;

passthrough

Added in v4.0.0 Source

Transforms values by returning the input unchanged in both directions.

When to use

Use when you need a schema transformation to connect two schemas that share the same type with no actual conversion.

Details

- Both decode and encode are no-ops. - Returns a shared singleton instance (no allocation per call). - By default, T and E must be the same type. Pass { strict: false } to bypass the type constraint.

See

Signature

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

Transforms values without changing them, typed so that E extends T — the encoded type is a subtype of the decoded type.

When to use

Use when you need a no-op schema transformation whose encoded side is more specific than its decoded side.

Details

- Both decode and encode are no-ops (same as passthrough). - Returns a shared singleton instance.

See

Signature

declare function passthroughSubtype<T, E>(): Transformation<T, E>;

Transforms values without changing them, typed so that T extends E, where the decoded type T is a subtype of the encoded type E.

When to use

Use when you need a no-op schema transformation whose decoded side is narrower than the encoded side.

Details

Both decode and encode are no-ops and return a shared singleton transformation.

See

Signature

declare function passthroughSupertype<T, E>(): Transformation<T, E>;

Converting

Decodes a string into a bigint and encodes a bigint back to a string.

When to use

Use when you need a schema transformation to parse large integer strings (e.g. database IDs, blockchain values).

Details

Decoding coerces the string to a bigint like BigInt(s). Encoding coerces the bigint to a string like String(n). Decoding fails if the string is not a valid bigint representation.

See

Signature

declare const bigintFromString: Transformation<bigint, string, never, never>;

Decodes epoch milliseconds into a Date and encodes a Date back to epoch milliseconds.

When to use

Use when you need a schema transformation for numeric timestamps represented as milliseconds since the Unix epoch.

Details

Decoding creates a Date from the number like new Date(ms). Encoding returns the Date timestamp like date.getTime().

Gotchas

This transformation does not validate date validity. NaN, Infinity, and -Infinity decode to invalid Date instances.

See

Signature

declare const dateFromMillis: Transformation<globalThis.Date, number>;

Decodes a string into a Date and encodes a Date back to a string.

When to use

Use when you need a schema transformation to parse date strings from APIs or user input.

Details

Decoding creates a Date from the string like new Date(s). Encoding converts the Date to an ISO string like date.toISOString(), returning "Invalid Date" for invalid dates.

See

Signature

declare const dateFromString: Transformation<globalThis.Date, string>;

Decodes a string into a number and encodes a number back to a string.

When to use

Use when you need a schema transformation to parse numeric strings from APIs, form data, or URL parameters.

Details

Decoding coerces the string to a number like Number(s). Encoding coerces the number to a string like String(n). This does not validate that the result is finite; combine with Schema.Finite or Schema.Int for stricter checks.

See

Signature

declare const numberFromString: Transformation<number, string, never, never>;

Decoding

fromFormData

Added in v4.0.0 Source

Decodes a FormData instance into a nested record using bracket-path keys and encodes object-like values back into FormData.

When to use

Use when you need a schema transformation for form or multipart payloads whose keys, such as user[name] or items[0], should become nested data.

Details

Decode preserves string and Blob leaves. Encode flattens nested objects and arrays into bracket-path entries and returns an empty FormData for non-object inputs.

See

Signature

declare const fromFormData: Transformation<unknown, FormData, never, never>;

Decodes a JSON string with JSON.parse and encodes a value with JSON.stringify.

When to use

Use when you need a schema transformation to decode JSON stored or transmitted as a string, usually before composing with another schema that validates the parsed structure.

Details

The reviver option is passed to JSON.parse during decoding. The replacer and space options are passed to JSON.stringify during encoding. Decode fails with InvalidValue for invalid JSON, and encode can fail with InvalidValue when JSON.stringify cannot serialize the value.

See

Signature

declare function fromJsonString(options?: {
  readonly replacer?: JsonReplacer;
  readonly reviver?: (this: any, key: string, value: any) => any;
  readonly space?: string | number;
}): Transformation<unknown, string>;

Decodes URLSearchParams into a nested record using bracket-path keys and encodes object-like values back into URLSearchParams.

When to use

Use when you need a schema transformation for query strings whose keys, such as filter[name] or items[0], should become nested data.

Details

Decode produces string leaves. Encode flattens nested objects and arrays into bracket-path entries and returns empty URLSearchParams for non-object inputs.

See

Signature

declare const fromURLSearchParams: Transformation<unknown, URLSearchParams, never, never>;

Encoding

Decodes a Base64-encoded string into a UTF-8 string and encodes a UTF-8 string back to a Base64 string.

When to use

Use when you need a schema transformation for text data transmitted as Base64 strings.

Details

Decoding parses the Base64 string into a UTF-8 string. Encoding writes the string as a Base64 string.

See

Signature

declare const stringFromBase64String: Transformation<string, string>;

Decodes a base64 (URL) encoded string into a UTF-8 string and encodes it back.

When to use

Use when you need a schema transformation for text data transmitted as Base64 URL-safe strings.

Details

Decoding parses the Base64 URL string into a UTF-8 string. Encoding writes the string as a Base64 URL string.

See

Signature

declare const stringFromBase64UrlString: Transformation<string, string>;

Decodes a hex encoded string into a UTF-8 string and encodes it back.

When to use

Use when you need a schema transformation for text data transmitted as hexadecimal strings.

Details

Decoding parses the hex string into a UTF-8 string. Encoding writes the string as a hex string.

See

Signature

declare const stringFromHexString: Transformation<string, string>;

Decodes a URI component encoded string into a UTF-8 string and encodes a UTF-8 string into a URI component encoded string.

When to use

Use when you need a schema transformation to store structured data in URL query parameters or fragments, such as composing with Schema.parseJson to round-trip JSON through a URL.

Details

Decoding calls decodeURIComponent and fails if the input contains malformed percent-encoding sequences. Encoding calls encodeURIComponent.

See

Signature

declare const stringFromUriComponent: Transformation<string, string>;

Decodes a Base64-encoded string into a Uint8Array and encodes a Uint8Array back to a Base64 string.

When to use

Use when you need a schema transformation for binary data transmitted as Base64 strings (e.g. file uploads, API payloads).

Details

Decoding parses the Base64 string into bytes. Encoding writes the byte array as a Base64 string.

See

  • fromJsonString
  • Schema.Uint8ArrayFromBase64 - a ready-made schema wrapping this transformation.

Signature

declare const uint8ArrayFromBase64String: Transformation<Uint8Array<ArrayBufferLike>, string>;

Guards

Returns true if u is a Transformation instance.

When to use

Use to check whether a value is already a schema transformation before wrapping it.

Details

- Pure predicate, no side effects. - Acts as a TypeScript type guard.

See

Signature

declare function isTransformation(u: unknown): u is Transformation<any, any, unknown, unknown>;

Models

Middleware

Added in v4.0.0 Source

Middleware that wraps the entire parsing Effect pipeline for both decode and encode directions.

When to use

Use when you need a schema middleware to catch or recover from parsing errors (e.g. Schema.catchDecoding), run side effects around the parsing pipeline, or access the full Effect rather than a single decoded value.

Details

Unlike Transformation, which operates on individual values via Getter, Middleware receives the full Effect produced by the inner schema and can intercept, modify, retry, or replace it.

- decode receives an Effect<Option<E>, Issue, RDE> and returns Effect<Option<T>, Issue, RDT>. - encode receives an Effect<Option<T>, Issue, RET> and returns Effect<Option<E>, Issue, REE>. - flip() swaps the decode and encode functions, producing a Middleware<E, T, ...>.

Typically constructed indirectly via Schema.middlewareDecoding or Schema.middlewareEncoding rather than instantiating this class directly.

See

Signature

declare class Middleware<in out T, in out E, RDE, RDT, RET, REE> {
  constructor<in out T, in out E, RDE, RDT, RET, REE>(decode: (effect: Effect<Option<E>, Issue, RDE>, options: ParseOptions) => Effect<Option<T>, Issue, RDT>, encode: (effect: Effect<Option<T>, Issue, RET>, options: ParseOptions) => Effect<Option<E>, Issue, REE>);
  readonly _tag: "Middleware";
  readonly decode: (effect: Effect<Option<E>, Issue, RDE>, options: ParseOptions) => Effect<Option<T>, Issue, RDT>;
  readonly encode: (effect: Effect<Option<T>, Issue, RET>, options: ParseOptions) => Effect<Option<E>, Issue, REE>;
  flip(): Middleware<E, T, RET, REE, RDE, RDT>;
}

Represents a bidirectional transformation between a decoded type T and an encoded type E, built from a pair of Getters.

When to use

Use when you need a schema transformation that defines how a schema converts between two representations. - You want to compose multiple transformations into a pipeline. - You want to flip a transformation to swap decode/encode.

Details

This is the primary building block for Schema.decodeTo, Schema.encodeTo, Schema.decode, Schema.encode, and Schema.link. Each direction is a SchemaGetter.Getter that handles optionality, failure, and Effect services.

- Immutable — flip() and compose() return new instances. - flip() swaps the decode and encode getters. - compose(other) chains: this.decode then other.decode for decoding, other.encode then this.encode for encoding.

See

  • make — construct from { decode, encode } getters
  • transform — construct from pure functions
  • transformOrFail — construct from effectful functions
  • Middleware — effect-pipeline-level alternative

Signature

declare class Transformation<in out T, in out E, RD = never, RE = never> {
  constructor<in out T, in out E, RD = never, RE = never>(decode: Getter<T, E, RD>, encode: Getter<E, T, RE>);
  readonly _tag: "Transformation";
  readonly "~effect/SchemaTransformation/Transformation": "~effect/SchemaTransformation/Transformation";
  readonly decode: Getter<T, E, RD>;
  readonly encode: Getter<E, T, RE>;
  compose<T2, RD2, RE2>(other: Transformation<T2, T, RD2, RE2>): Transformation<T2, E, RD | RD2, RE | RE2>;
  flip(): Transformation<E, T, RE, RD>;
}

Transforming

Decodes a string into a BigDecimal and encodes a BigDecimal back to its string representation.

When to use

Use when you need a schema transformation to parse decimal number strings from APIs or user input.

Details

Decoding calls BigDecimal.fromString(s) and fails with InvalidValue if the string is not a valid BigDecimal representation. Encoding returns BigDecimal.format(bd).

Signature

declare const bigDecimalFromString: Transformation<BigDecimal.BigDecimal, string>;

capitalize

Added in v4.0.0 Source

Transforms strings by capitalizing the first character on decode. Encode is passthrough.

When to use

Use when you need a schema transformation to normalize display names or titles.

Details

Decoding uppercases the first character and leaves the rest unchanged. Encoding is passthrough.

See

Signature

declare function capitalize(): Transformation<string, string>;

Decodes a date-time string into a DateTime.Utc and encodes it back to an ISO string.

When to use

Use when you need a schema transformation to decode date-time strings to a normalized DateTime.Utc and encode back as a UTC ISO string.

Details

Decode accepts strings supported by DateTime.make, converts the result to UTC, and fails with InvalidValue when parsing fails. Encode uses DateTime.formatIso.

See

Signature

declare const dateTimeUtcFromString: Transformation<DateTime.Utc, string>;

Decodes a zoned date-time string into a DateTime.Zoned and encodes it back to an ISO zoned string.

When to use

Use when you need a schema transformation for ISO zoned date-time strings that decode to DateTime.Zoned and encode with DateTime.formatIsoZoned.

Details

Decode uses DateTime.makeZonedFromString and fails with InvalidValue when the input is not a valid zoned date-time. Encode uses DateTime.formatIsoZoned.

See

  • dateTimeUtcFromString for date-time strings that should decode to DateTime.Utc and encode as UTC ISO strings

Signature

declare const dateTimeZonedFromString: Transformation<DateTime.Zoned, string>;

Decodes a number of milliseconds into a Duration and encodes a Duration back to milliseconds.

When to use

Use when you need a schema transformation to decode timeouts, delays, elapsed intervals, or other duration values stored as millisecond counts.

Details

Decode creates a duration from the number, and encode returns the duration length in milliseconds.

See

Signature

declare const durationFromMillis: Transformation<Duration.Duration, number>;

Decodes a bigint (nanoseconds) into a Duration and encodes a Duration back to bigint nanoseconds.

When to use

Use when you need a schema transformation for nanosecond-precision timestamps or intervals.

Details

Decoding always succeeds and creates a Duration from nanoseconds. Encoding fails with InvalidValue if the Duration cannot be represented as a bigint, such as Duration.infinity.

See

Signature

declare const durationFromNanos: Transformation<Duration.Duration, bigint>;

Decodes a string into a Duration and encodes a Duration back to a parseable string.

When to use

Use when you need a schema transformation to parse human-readable duration strings from APIs, config, or user input.

Details

Decoding accepts any string that Duration.fromInput can parse, including "Infinity" and "-Infinity". Encoding returns String(duration), producing strings such as "2000 millis" or "10 nanos" that round-trip through the parser.

See

Signature

declare const durationFromString: Transformation<Duration.Duration, string>;

Decodes T | null | undefined into Option<T> and encodes Option<T> back to T | null or T | undefined depending on the provided options.onNoneEncoding (defaults to undefined).

When to use

Use when you need a schema transformation to convert nullish API fields to Option when both null and undefined represent absence.

Details

Decoding maps null and undefined to Option.none() and all other values to Option.some(value). Encoding maps Option.none() to null or undefined according to options.onNoneEncoding, and maps Option.some(value) to value. The transformation is pure and synchronous.

See

Signature

declare function optionFromNullishOr<T>(options?: {
  onNoneEncoding: null | undefined;
}): Transformation<Option<T>, T | null | undefined>;

Decodes T | null into Option<T> and encodes Option<T> back to T | null.

When to use

Use when you need a schema transformation to convert nullable API fields to Option.

Details

Decoding maps null to Option.none() and non-null values to Option.some(value). Encoding maps Option.none() to null and Option.some(value) to value. The transformation is pure and synchronous.

See

Signature

declare function optionFromNullOr<T>(): Transformation<Option<T>, T | null>;

Decodes optional values into Option<T> and encodes Option.none() back to an omitted optional value.

When to use

Use when you need a schema transformation to convert optional (possibly undefined) values to Option.

Details

Decoding maps an absent or undefined value to Some(None) and a present value to Some(Some(v)). Encoding maps Some(None) to None to omit the value, and maps Some(Some(v)) to Some(v). This uses transformOptional under the hood and filters out undefined on decode.

See

Signature

declare function optionFromOptional<T>(): Transformation<Option<T>, T | undefined>;

Decodes an optional struct key into Option<T> and encodes Option<T> back to an optional key.

When to use

Use when you need a schema transformation to convert optional struct keys (declared with Schema.optionalKey) to Option values.

Details

Decoding maps an absent key (None) to Some(None) and a present key (Some(v)) to Some(Some(v)). Encoding maps Some(None) to None to omit the key, and maps Some(Some(v)) to Some(v). This uses transformOptional under the hood.

See

Signature

declare function optionFromOptionalKey<T>(): Transformation<Option<T>, T>;

Decodes T | undefined into Option<T> and encodes Option.none() back to undefined.

When to use

Use when you need a schema transformation to convert API fields that use undefined for absence to Option.

Details

Decoding maps undefined to Option.none() and non-undefined values to Option.some(value). Encoding maps Option.none() to undefined and Option.some(value) to value. The transformation is pure and synchronous.

See

Signature

declare function optionFromUndefinedOr<T>(): Transformation<Option<T>, T | undefined>;

snakeToCamel

Added in v4.0.0 Source

Transforms strings by converting snake_case to camelCase on decode and camelCase to snake_case on encode.

When to use

Use when you need a schema transformation to convert API field names between snake_case and camelCase conventions.

Details

Decoding converts values such as "my_field_name" to "myFieldName". Encoding converts values such as "myFieldName" back to "my_field_name". The transformation is round-trippable for standard snake_case and camelCase.

See

Signature

declare function snakeToCamel(): Transformation<string, string>;

Transforms a string into a record of key-value pairs and encodes a record of key-value pairs into a string.

When to use

Use when you need a schema transformation to parse query-string-like or config-file-like strings into records.

Details

Decoding splits the string by separator (default ",") into pairs, then splits each pair by keyValueSeparator (default "="). Encoding joins the record back into a string using the same separators. The transformation is round-trippable when keys and values do not contain the separators.

See

Signature

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

Decodes a string into a DateTime.TimeZone and encodes a time zone back to its string representation.

When to use

Use when you need a schema transformation to accept either an IANA time-zone identifier or an offset string and produce a general DateTime.TimeZone.

Details

Accepted decode inputs include valid IANA identifiers and offset strings such as "+03:00". Decode fails with InvalidValue when the string cannot be parsed as a time zone.

See

Signature

declare const timeZoneFromString: Transformation<DateTime.TimeZone, string>;

Decodes an IANA time-zone identifier string into a DateTime.TimeZone.Named and encodes a named time zone back to its id.

When to use

Use when you need a schema transformation to accept only IANA time-zone identifier strings and produce DateTime.TimeZone.Named values.

Details

Decode fails with InvalidValue when the string is not a valid IANA time-zone identifier.

See

  • timeZoneFromString for time-zone strings that may be either IANA identifiers or offset strings

Signature

declare const timeZoneNamedFromString: Transformation<DateTime.TimeZone.Named, string>;

Decodes a numeric time-zone offset in milliseconds into a DateTime.TimeZone.Offset and encodes it back to the offset number.

When to use

Use when you need a schema transformation to represent fixed-offset time zones with numeric millisecond offsets.

Details

Decode uses DateTime.zoneMakeOffset; encode returns the offset's offset field.

See

Signature

declare const timeZoneOffsetFromNumber: Transformation<DateTime.TimeZone.Offset, number>;

toLowerCase

Added in v4.0.0 Source

Transforms strings by lowercasing on decode. Encode is passthrough.

When to use

Use when you need a schema transformation to normalize strings to lowercase (e.g. email addresses).

Details

Decoding applies String.prototype.toLowerCase(). Encoding is passthrough. This is not round-trippable if the original had uppercase characters.

See

Signature

declare function toLowerCase(): Transformation<string, string>;

toUpperCase

Added in v4.0.0 Source

Transforms strings by uppercasing on decode. Encode is passthrough.

When to use

Use when you need a schema transformation to normalize strings to uppercase (e.g. country codes).

Details

Decoding applies String.prototype.toUpperCase(). Encoding is passthrough. This is not round-trippable if the original had lowercase characters.

See

Signature

declare function toUpperCase(): Transformation<string, string>;

transform

Added in v3.10.0 Source

Creates a Transformation from pure (sync, infallible) decode and encode functions.

When to use

Use when you need an infallible schema transformation that does not require Effect services.

Details

- Each function receives the input and returns the output directly. - Skips None inputs (missing keys) — functions are only called on present values. - Does not allocate Effects internally; uses optimized sync path.

See

Signature

declare function transform<T, E>(options: {
  readonly decode: (input: E) => T;
  readonly encode: (input: T) => E;
}): Transformation<T, E>;

Creates a Transformation where decode and encode operate on Option values, giving full control over missing-key handling.

When to use

Use when you need a schema transformation to produce or consume Option.None for absent keys. - You are working with optional struct fields.

Details

- Each function receives Option<input> and returns Option<output>. - Option.None input means the key is absent; returning Option.None omits the key from the output. - Pure and synchronous.

See

Signature

declare function transformOptional<T, E>(options: {
  readonly decode: (input: Option<E>) => Option<T>;
  readonly encode: (input: Option<T>) => Option<E>;
}): Transformation<T, E>;

Creates a Transformation from effectful decode and encode functions that can fail with Issue.

When to use

Use when you need a schema transformation that may fail or require Effect services.

Details

- Each function receives the input value and ParseOptions. - Must return an Effect that succeeds with the output or fails with Issue. - Skips None inputs (missing keys) — functions are only called on present values.

See

  • transform — for infallible, pure transformations
  • transformOptional — for transformations that handle missing keys
  • make — for transformations from existing Getters

Signature

declare function transformOrFail<T, E, RD = never, RE = never>(options: {
  readonly decode: (e: E, options: ParseOptions) => Effect<T, Issue, RD>;
  readonly encode: (t: T, options: ParseOptions) => Effect<E, Issue, RE>;
}): Transformation<T, E, RD, RE>;

trim

Added in v4.0.0 Source

Transforms strings by trimming whitespace on decode. Encode is passthrough (no change).

When to use

Use when you need a schema transformation to normalize user input by stripping leading/trailing whitespace.

Details

Decoding applies String.prototype.trim(). Encoding is passthrough and returns the string unchanged. This is not round-trippable if the original had whitespace.

See

Signature

declare function trim(): Transformation<string, string>;

uncapitalize

Added in v4.0.0 Source

Transforms strings by lowercasing the first character on decode. Encode is passthrough.

When to use

Use when you need a schema transformation to normalize identifiers or field names.

Details

Decoding lowercases the first character and leaves the rest unchanged. Encoding is passthrough.

See

Signature

declare function uncapitalize(): Transformation<string, string>;

Decodes a string into a URL and encodes a URL back to its href string.

When to use

Use when you need a schema transformation to parse URL strings from user input or API responses.

Details

Decoding checks URL.canParse(s) and fails with InvalidValue if the string is not a valid URL. Encoding returns url.href.

See

Signature

declare const urlFromString: Transformation<URL, string>;