TemplateLiteralAST node representing a TypeScript template literal type
(e.g. `user_${string}`).
Details
parts is an array of AST nodes; each part contributes to matching
strings at runtime.
export class class TemplateLiteralclass TemplateLiteral {
_tag: 'TemplateLiteral';
parts: ReadonlyArray<AST>;
encodedParts: ReadonlyArray<TemplateLiteralPart>;
getParser: (recur: (ast: AST) => SchemaParser.Parser) => SchemaParser.Parser;
getExpected: () => string;
matchPart: (s: string, options: ParseOptions) => string | undefined;
asTemplateLiteralParser: () => Arrays;
annotations: Schema.Annotations.Annotations | undefined;
checks: Checks | undefined;
encoding: Encoding | undefined;
context: Context | undefined;
toString: () => string;
}
AST node representing a TypeScript template literal type
(e.g. `user_${string}`).
Details
parts is an array of AST nodes; each part contributes to matching
strings at runtime.
TemplateLiteral extends class BaseRepresents the abstract base class for all
AST
node variants.
Details
Every AST node extends Base and inherits these fields:
annotations — user-supplied metadata (identifier, title, description,
arbitrary keys).
checks — optional
Checks
for post-type-match validation.
encoding — optional
Encoding
chain for type ↔ wire
transformations.
context — optional
Context
for per-property metadata.
Subclasses add a _tag discriminant and variant-specific data.
Base {
readonly TemplateLiteral._tag: "TemplateLiteral"_tag = "TemplateLiteral"
readonly TemplateLiteral.parts: ReadonlyArray<AST>parts: interface ReadonlyArray<T>ReadonlyArray<type AST =
| Declaration
| Null
| Undefined
| Void
| Never
| Unknown
| Any
| String
| Number
| Boolean
| BigInt
| Symbol
| Literal
| UniqueSymbol
| ObjectKeyword
| Enum
| TemplateLiteral
| Arrays
| Objects
| Union<AST>
| Suspend
Discriminated union of all AST node types.
Details
Every Schema has an .ast property of this type. Use the guard functions
(
isString
,
isObjects
, etc.) to narrow to a specific variant,
then access variant-specific fields.
- All variants share the
Base
fields:
annotations, checks,
encoding, context.
- Discriminate on the
_tag field (e.g. "String", "Objects", "Union").
AST>
/** @internal */
readonly TemplateLiteral.encodedParts: readonly TemplateLiteralPart[]encodedParts: interface ReadonlyArray<T>ReadonlyArray<type TemplateLiteralPart =
| String
| Number
| BigInt
| Literal
| TemplateLiteral
| Union<TemplateLiteralPart>
TemplateLiteralPart>
constructor(
parts: ReadonlyArray<AST>parts: interface ReadonlyArray<T>ReadonlyArray<type AST =
| Declaration
| Null
| Undefined
| Void
| Never
| Unknown
| Any
| String
| Number
| Boolean
| BigInt
| Symbol
| Literal
| UniqueSymbol
| ObjectKeyword
| Enum
| TemplateLiteral
| Arrays
| Objects
| Union<AST>
| Suspend
Discriminated union of all AST node types.
Details
Every Schema has an .ast property of this type. Use the guard functions
(
isString
,
isObjects
, etc.) to narrow to a specific variant,
then access variant-specific fields.
- All variants share the
Base
fields:
annotations, checks,
encoding, context.
- Discriminate on the
_tag field (e.g. "String", "Objects", "Union").
AST>,
annotations: anyannotations?: import SchemaSchema.declareAnnotations.type Schema.Annotations.Annotations = /*unresolved*/ anyAnnotations,
checks: Checkschecks?: type Checks = readonly [
Check<any>,
...Check<any>[]
]
Non-empty array of validation
Check
values attached to an AST node
via
Base.checks
.
Details
Checks are run after basic type matching succeeds. They represent
refinements like minLength, pattern, int, etc.
Checks,
encoding: Encodingencoding?: type Encoding = readonly [Link, ...Link[]]A non-empty chain of
Link
values representing the transformation
steps between a schema's decoded (type) form and its encoded (wire) form.
Details
Stored on
Base.encoding
. When undefined, the node has no
encoding transformation (type and encoded forms are identical).
Encoding,
context: Contextcontext?: class Contextclass Context {
isOptional: boolean;
isMutable: boolean;
defaultValue: Encoding | undefined;
annotations: Schema.Annotations.Key<unknown> | undefined;
}
Represents per-property metadata attached to AST nodes via
Base.context
.
Details
Tracks whether a property key is optional, mutable, has a constructor
default, or carries key-level annotations. Typically set by helpers like
optionalKey
and Schema.mutableKey.
isOptional — the property key may be absent from the input.
isMutable — the property is readonly when false.
defaultValue — an
Encoding
applied during construction to
supply missing values.
annotations — key-level annotations (e.g. description of the key
itself).
Context
) {
super(annotations: anyannotations, checks: Checkschecks, encoding: Encodingencoding, context: Contextcontext)
const const encodedParts: TemplateLiteralPart[]encodedParts: interface Array<T>Array<type TemplateLiteralPart =
| String
| Number
| BigInt
| Literal
| TemplateLiteral
| Union<TemplateLiteralPart>
TemplateLiteralPart> = []
for (const const part: ASTpart of parts: ReadonlyArray<AST>parts) {
const const encoded: ASTencoded = const toEncoded: anyReturns the encoded (wire-format) AST by flipping and then stripping
encodings.
Details
Equivalent to toType(flip(ast)). This gives you the AST that describes
the shape of the serialized/encoded data.
- Memoized: same input reference → same output reference.
Example (Getting the encoded AST)
import { Schema, SchemaAST } from "effect"
const schema = Schema.NumberFromString
const encodedAst = SchemaAST.toEncoded(schema.ast)
console.log(encodedAst._tag) // "String"
toEncoded(const part: ASTpart)
if (function isTemplateLiteralPart(
ast: AST
): ast is TemplateLiteralPart
isTemplateLiteralPart(const encoded: ASTencoded)) {
const encodedParts: TemplateLiteralPart[]encodedParts.Array<TemplateLiteralPart>.push(...items: TemplateLiteralPart[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push(const encoded: TemplateLiteralPartencoded)
} else {
throw new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error(`Invalid TemplateLiteral part ${const encoded: anyencoded._tag}`)
}
}
this.TemplateLiteral.parts: ReadonlyArray<AST>parts = parts: ReadonlyArray<AST>parts
this.TemplateLiteral.encodedParts: readonly TemplateLiteralPart[]encodedParts = const encodedParts: TemplateLiteralPart[]encodedParts
}
/** @internal */
TemplateLiteral.getParser(recur: (ast: AST) => SchemaParser.Parser): SchemaParser.ParsergetParser(recur: (ast: AST) => SchemaParser.Parserrecur: (ast: ASTast: type AST =
| Declaration
| Null
| Undefined
| Void
| Never
| Unknown
| Any
| String
| Number
| Boolean
| BigInt
| Symbol
| Literal
| UniqueSymbol
| ObjectKeyword
| Enum
| TemplateLiteral
| Arrays
| Objects
| Union<AST>
| Suspend
Discriminated union of all AST node types.
Details
Every Schema has an .ast property of this type. Use the guard functions
(
isString
,
isObjects
, etc.) to narrow to a specific variant,
then access variant-specific fields.
- All variants share the
Base
fields:
annotations, checks,
encoding, context.
- Discriminate on the
_tag field (e.g. "String", "Objects", "Union").
AST) => import SchemaParserSchemaParser.Parser): import SchemaParserSchemaParser.Parser {
const const parser: SchemaParser.Parserparser = recur: (ast: AST) => SchemaParser.Parserrecur(this.TemplateLiteral.asTemplateLiteralParser(): ArraysasTemplateLiteralParser())
return (oinput: Option.Option<unknown>oinput: import OptionOption.type Option.Option = /*unresolved*/ anyOption<unknown>, options: ParseOptions(parameter) options: {
errors: "first" | "all" | undefined;
onExcessProperty: "ignore" | "error" | "preserve" | undefined;
propertyOrder: "none" | "original" | undefined;
disableChecks: boolean | undefined;
concurrency: number | "unbounded" | undefined;
}
options: ParseOptions) =>
import EffectEffect.mapBothEager(const parser: SchemaParser.Parser
;(
input: Option.Option<unknown>,
options: ParseOptions
) =>
Effect.Effect<
Option.Option<unknown>,
SchemaIssue.Issue,
any
>
parser(oinput: Option.Option<unknown>oinput, options: ParseOptions(parameter) options: {
errors: "first" | "all" | undefined;
onExcessProperty: "ignore" | "error" | "preserve" | undefined;
propertyOrder: "none" | "original" | undefined;
disableChecks: boolean | undefined;
concurrency: number | "unbounded" | undefined;
}
options), {
onSuccess: () => Option.Option<unknown>onSuccess: () => oinput: Option.Option<unknown>oinput,
onFailure: (issue: any) => SchemaIssue.CompositeonFailure: (issue: SchemaIssue.Issueissue) => new import SchemaIssueSchemaIssue.constructor Composite(ast: AST, actual: Option.Option<unknown>, issues: readonly [SchemaIssue.Issue, ...Array<SchemaIssue.Issue>]): SchemaIssue.CompositeRepresents a schema issue that groups multiple child issues under a single schema node.
When to use
Use when you need to walk the issue tree for struct/tuple schemas that collect
all field errors rather than failing on the first.
Details
issues is a non-empty readonly array (at least one child).
actual is Option.some(value) when the input was present, or
Option.none() when absent.
- Formatters flatten
Composite by recursing into each child.
Composite(this, oinput: Option.Option<unknown>oinput, [issue: SchemaIssue.Issueissue])
})
}
/** @internal */
TemplateLiteral.getExpected(): stringgetExpected(): string {
return "string"
}
/** @internal */
TemplateLiteral.matchPart(s: string, options: ParseOptions): string | undefinedmatchPart(s: strings: string, options: ParseOptions(parameter) options: {
errors: "first" | "all" | undefined;
onExcessProperty: "ignore" | "error" | "preserve" | undefined;
propertyOrder: "none" | "original" | undefined;
disableChecks: boolean | undefined;
concurrency: number | "unbounded" | undefined;
}
options: ParseOptions): string | undefined {
return function segmentTemplateLiteralParts(
parts: ReadonlyArray<TemplateLiteralPart>,
input: string,
options: ParseOptions
): Array<string> | undefined
segmentTemplateLiteralParts(this.TemplateLiteral.encodedParts: readonly TemplateLiteralPart[]encodedParts, s: strings, options: ParseOptions(parameter) options: {
errors: "first" | "all" | undefined;
onExcessProperty: "ignore" | "error" | "preserve" | undefined;
propertyOrder: "none" | "original" | undefined;
disableChecks: boolean | undefined;
concurrency: number | "unbounded" | undefined;
}
options) === var undefinedundefined ? var undefinedundefined : s: strings
}
/** @internal */
TemplateLiteral.asTemplateLiteralParser(): ArraysasTemplateLiteralParser(): class Arraysclass Arrays {
_tag: 'Arrays';
isMutable: boolean;
elements: ReadonlyArray<AST>;
rest: ReadonlyArray<AST>;
encodingChecks: Checks | undefined;
getParser: (recur: (ast: AST) => SchemaParser.Parser) => SchemaParser.Parser;
_rebuild: (recur: (ast: AST) => AST, checks: Checks | undefined, encodingChecks: Checks | undefined) => Arrays;
recur: (recur: (ast: AST) => AST) => Arrays;
flip: (recur: (ast: AST) => AST) => Arrays;
getExpected: () => string;
annotations: Schema.Annotations.Annotations | undefined;
checks: Checks | undefined;
encoding: Encoding | undefined;
context: Context | undefined;
toString: () => string;
}
AST node for array-like types — both tuples and arrays.
When to use
Use when constructing or inspecting AST nodes for tuple or array-like schemas,
including rest elements.
Details
elements — positional element types (tuple elements). An element is
optional if its
Context.isOptional
is true.
rest — the rest/variadic element types. When non-empty, the first
entry is the "spread" type (e.g. ...Array<string>), and subsequent
entries are trailing positional elements after the spread.
isMutable — whether the resulting array is readonly (false) or
mutable (true).
Gotchas
Construction enforces TypeScript ordering rules: a required element
cannot follow an optional one, and an optional element cannot follow a
rest element.
Example (Inspecting a tuple AST)
import { Schema, SchemaAST } from "effect"
const schema = Schema.Tuple([Schema.String, Schema.Number])
const ast = schema.ast
if (SchemaAST.isArrays(ast)) {
console.log(ast.elements.length) // 2
console.log(ast.rest.length) // 0
}
Arrays {
const const tuple: Arraysconst tuple: {
_tag: 'Arrays';
isMutable: boolean;
elements: ReadonlyArray<AST>;
rest: ReadonlyArray<AST>;
encodingChecks: Checks | undefined;
getParser: (recur: (ast: AST) => SchemaParser.Parser) => SchemaParser.Parser;
_rebuild: (recur: (ast: AST) => AST, checks: Checks | undefined, encodingChecks: Checks | undefined) => Arrays;
recur: (recur: (ast: AST) => AST) => Arrays;
flip: (recur: (ast: AST) => AST) => Arrays;
getExpected: () => string;
annotations: Schema.Annotations.Annotations | undefined;
checks: Checks | undefined;
encoding: Encoding | undefined;
context: Context | undefined;
toString: () => string;
}
tuple = new constructor Arrays(isMutable: boolean, elements: ReadonlyArray<AST>, rest: ReadonlyArray<AST>, annotations?: Schema.Annotations.Annotations, checks?: Checks, encoding?: Encoding, context?: Context, encodingChecks?: Checks): ArraysAST node for array-like types — both tuples and arrays.
When to use
Use when constructing or inspecting AST nodes for tuple or array-like schemas,
including rest elements.
Details
elements — positional element types (tuple elements). An element is
optional if its
Context.isOptional
is true.
rest — the rest/variadic element types. When non-empty, the first
entry is the "spread" type (e.g. ...Array<string>), and subsequent
entries are trailing positional elements after the spread.
isMutable — whether the resulting array is readonly (false) or
mutable (true).
Gotchas
Construction enforces TypeScript ordering rules: a required element
cannot follow an optional one, and an optional element cannot follow a
rest element.
Example (Inspecting a tuple AST)
import { Schema, SchemaAST } from "effect"
const schema = Schema.Tuple([Schema.String, Schema.Number])
const ast = schema.ast
if (SchemaAST.isArrays(ast)) {
console.log(ast.elements.length) // 2
console.log(ast.rest.length) // 0
}
Arrays(false, this.TemplateLiteral.parts: ReadonlyArray<AST>parts.ReadonlyArray<AST>.map<AST>(callbackfn: (value: AST, index: number, array: readonly AST[]) => AST, thisArg?: any): AST[]Calls a defined callback function on each element of an array, and returns an array that contains the results.
map(const partFromString: anypartFromString), [])
return function decodeTo<A extends AST>(
from: AST,
to: A,
transformation: SchemaTransformation.Transformation<
any,
any,
any,
any
>
): A
Attaches a Transformation to the to AST, making it decode from the
from AST and encode back to it.
Details
This is the low-level primitive behind Schema.transform and
Schema.transformOrFail. It appends a
Link
to the to node's
encoding chain.
- Returns a new AST with the same type as
to.
decodeTo(
const string: Stringconst string: {
_tag: 'String';
getParser: () => SchemaParser.Parser;
matchPart: (s: string, options: ParseOptions) => string | undefined;
getExpected: () => string;
annotations: Schema.Annotations.Annotations | undefined;
checks: Checks | undefined;
encoding: Encoding | undefined;
context: Context | undefined;
toString: () => string;
}
Provides the singleton
String
AST instance.
When to use
Use as the shared SchemaAST node for unconstrained JavaScript strings.
string,
const tuple: Arraysconst tuple: {
_tag: 'Arrays';
isMutable: boolean;
elements: ReadonlyArray<AST>;
rest: ReadonlyArray<AST>;
encodingChecks: Checks | undefined;
getParser: (recur: (ast: AST) => SchemaParser.Parser) => SchemaParser.Parser;
_rebuild: (recur: (ast: AST) => AST, checks: Checks | undefined, encodingChecks: Checks | undefined) => Arrays;
recur: (recur: (ast: AST) => AST) => Arrays;
flip: (recur: (ast: AST) => AST) => Arrays;
getExpected: () => string;
annotations: Schema.Annotations.Annotations | undefined;
checks: Checks | undefined;
encoding: Encoding | undefined;
context: Context | undefined;
toString: () => string;
}
tuple,
new import SchemaTransformationSchemaTransformation.constructor Transformation<any, string, any, never>(decode: SchemaGetter.Getter<any, string, any>, encode: SchemaGetter.Getter<string, any, never>): SchemaTransformation.Transformation<any, string, any, never>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.
Example (Composing two transformations)
import { SchemaTransformation } from "effect"
const trimAndLower = SchemaTransformation.trim().compose(
SchemaTransformation.toLowerCase()
)
// decode: trim then lowercase
// encode: passthrough (both directions)
Transformation(
import SchemaGetterSchemaGetter.function transformOrFail<T, E, R = never>(
f: (
e: E,
options: SchemaAST.ParseOptions
) => Effect.Effect<T, SchemaIssue.Issue, R>
): Getter<T, E, R>
Creates a getter that applies a fallible, 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.
Example (Parsing with failure)
import { Effect, Option, SchemaGetter, SchemaIssue } from "effect"
const safeParseInt = SchemaGetter.transformOrFail<number, string>(
(s) => {
const n = parseInt(s, 10)
return isNaN(n)
? Effect.fail(new SchemaIssue.InvalidValue(Option.some(s), { message: "not an integer" }))
: Effect.succeed(n)
}
)
transformOrFail((s: strings: string, options: ParseOptions(parameter) options: {
errors: "first" | "all" | undefined;
onExcessProperty: "ignore" | "error" | "preserve" | undefined;
propertyOrder: "none" | "original" | undefined;
disableChecks: boolean | undefined;
concurrency: number | "unbounded" | undefined;
}
options) => {
const const segments: string[] | undefinedsegments = function segmentTemplateLiteralParts(
parts: ReadonlyArray<TemplateLiteralPart>,
input: string,
options: ParseOptions
): Array<string> | undefined
segmentTemplateLiteralParts(this.TemplateLiteral.encodedParts: readonly TemplateLiteralPart[]encodedParts, s: strings, options: ParseOptions(parameter) options: {
errors: "first" | "all" | undefined;
onExcessProperty: "ignore" | "error" | "preserve" | undefined;
propertyOrder: "none" | "original" | undefined;
disableChecks: boolean | undefined;
concurrency: number | "unbounded" | undefined;
}
options)
if (const segments: string[] | undefinedsegments !== var undefinedundefined) return import EffectEffect.succeed(const segments: string[]segments)
return import EffectEffect.fail(
new import SchemaIssueSchemaIssue.constructor InvalidValue(actual: Option.Option<unknown>, annotations?: Schema.Annotations.Issue | undefined): SchemaIssue.InvalidValueRepresents a schema issue produced when the input has the correct type but its value violates a
constraint (e.g. a string that is too short, a number out of range).
When to use
Use when you need to detect constraint violations from Schema.filter,
Schema.minLength, Schema.greaterThan, or similar checks.
Details
actual is Option.some(value) when the failing value is known, or
Option.none() when absent.
annotations optionally carries a message string for formatting.
- The default formatter renders this as
"Invalid data <actual>" unless a
custom message annotation is provided.
Example (Returning InvalidValue from a custom filter)
import { Option, SchemaIssue } from "effect"
const issue = new SchemaIssue.InvalidValue(
Option.some(""),
{ message: "must not be empty" }
)
console.log(String(issue))
// "must not be empty"
InvalidValue(import OptionOption.some(s: strings), {
message: stringmessage: `Expected a string matching template literal parts, got ${import formatformat(s: strings)}`
})
)
}),
import SchemaGetterSchemaGetter.function transform<T, E>(
f: (e: E) => T
): Getter<T, E>
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.
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))
})
)
transform((parts: anyparts) => parts: anyparts.join(""))
)
)
}
}