Skip to main content Link Search Menu Expand Document (external link)

Schema.ts overview

An extension to the effect/Schema module: Schema instances, codecs and filters for number and date formatting, parsing and comparison, and for templating.

Mental model

  • A codec (FiniteFromString, DateTimeFromString, Template…) converts between a string (its encoded side) and a typed value (its decoded side). It is driven by a format object (MNumberBase10Format, MDateTimeFormat + MDateTimeContext, MTemplate) that is used both for parsing and for formatting.
  • DateTime is the Schema of a MDateTime. Its encoded side is an object { timestamp, zoneOffset }, so that a MDateTime can be serialized (JSON…) and generated for property-based testing (Arbitrary), e.g. when it is a field of a MSchemaData class.
  • The filters (isBetweenDateTime…) check that a MDateTime is ordered with respect to given bounds. They are built with the Schema.makeIs* functions from MDateTime.Order.
  • When a transformation fails, the issue carries a message that explains why.

Common tasks

  • Parse/format a number: FiniteFromString, BigDecimalFromString
  • Parse/format a date-time: DateTimeFromString, DateFromString, DateTimeZonedFromString
  • Convert between date-time objects: DateFromDateTime, DateTimeZonedFromDateTime
  • Parse/format a structured text: Template
  • Constrain a MDateTime: isGreaterThanDateTime, isGreaterThanOrEqualToDateTime, isLessThanDateTime, isLessThanOrEqualToDateTime, isBetweenDateTime

Gotchas

  • The filters on MDateTime compare timestamps and ignore the zone offset. Their bounds do not help Arbitrary to generate candidates: candidates are generated at random, then filtered.

Quickstart

Example (Parsing a number and constraining a MDateTime)

import { Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MNumberBase10Format from "@parischap/effect-lib/MNumberBase10Format"
import * as MSchema from "@parischap/effect-lib/MSchema"

const price = MSchema.FiniteFromString(MNumberBase10Format.frenchStyleNumber)
// 1024.56
console.log(Schema.decodeUnknownSync(price)("1 024,56"))

const dateTime = MSchema.DateTime.check(MSchema.isGreaterThanOrEqualToDateTime(MDateTime.fromTimestampOrThrow(0)))
// Throws a `SchemaError`: Expected a value greater than or equal to 1970-01-01T00:00:00.000+00:00
Schema.decodeUnknownSync(dateTime)(MDateTime.fromTimestampOrThrow(-1))

See

  • MDateTime.Order — the Order the filters are built on

Exports Grouped by Category


Filters

isBetweenDateTime

A filter that checks that a MDateTime is within a range

  • Compares timestamps: the zone offset is ignored.
  • The bounds are inclusive unless exclusiveMinimum or exclusiveMaximum is true.
  • Fails with the message Expected a value between <minimum> and <maximum>, followed by (excluded) after an excluded bound.

Example (Checking that a MDateTime is within the first second of the epoch)

import { Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MSchema from "@parischap/effect-lib/MSchema"

const schema = MSchema.DateTime.check(
  MSchema.isBetweenDateTime({
    minimum: MDateTime.fromTimestampOrThrow(0),
    maximum: MDateTime.fromTimestampOrThrow(1000),
    exclusiveMaximum: true
  })
)

// Passes
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(999))
// Throws a `SchemaError`: Expected a value between 1970-01-01T00:00:00.000+00:00 and
// 1970-01-01T00:00:01.000+00:00 (excluded)
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(1000))

Signature

declare const isBetweenDateTime: (
  options: {
    readonly minimum: MDateTime.Type
    readonly maximum: MDateTime.Type
    readonly exclusiveMinimum?: boolean | undefined
    readonly exclusiveMaximum?: boolean | undefined
  },
  annotations?: Schema.Annotations.Filter
) => Filter<MDateTime.Type>

Source

isGreaterThanDateTime

A filter that checks that a MDateTime is strictly later than a given MDateTime

  • Compares timestamps: the zone offset is ignored.
  • Fails with the message Expected a value greater than <bound>.

Example (Checking that a MDateTime is after the epoch)

import { Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MSchema from "@parischap/effect-lib/MSchema"

const schema = MSchema.DateTime.check(MSchema.isGreaterThanDateTime(MDateTime.fromTimestampOrThrow(0)))

// Passes
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(1))
// Throws a `SchemaError`: Expected a value greater than 1970-01-01T00:00:00.000+00:00
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(0))

See

  • isGreaterThanOrEqualToDateTime — inclusive version

Signature

declare const isGreaterThanDateTime: (
  exclusiveMinimum: MDateTime.Type,
  annotations?: Schema.Annotations.Filter
) => Filter<MDateTime.Type>

Source

isGreaterThanOrEqualToDateTime

A filter that checks that a MDateTime is later than or equal to a given MDateTime

  • Compares timestamps: the zone offset is ignored.
  • Fails with the message Expected a value greater than or equal to <bound>.

Example (Checking that a MDateTime is not before the epoch)

import { Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MSchema from "@parischap/effect-lib/MSchema"

const schema = MSchema.DateTime.check(MSchema.isGreaterThanOrEqualToDateTime(MDateTime.fromTimestampOrThrow(0)))

// Passes
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(0))
// Throws a `SchemaError`: Expected a value greater than or equal to 1970-01-01T00:00:00.000+00:00
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(-1))

See

  • isGreaterThanDateTime — exclusive version

Signature

declare const isGreaterThanOrEqualToDateTime: (
  minimum: MDateTime.Type,
  annotations?: Schema.Annotations.Filter
) => Filter<MDateTime.Type>

Source

isLessThanDateTime

A filter that checks that a MDateTime is strictly earlier than a given MDateTime

  • Compares timestamps: the zone offset is ignored.
  • Fails with the message Expected a value less than <bound>.

Example (Checking that a MDateTime is before the epoch)

import { Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MSchema from "@parischap/effect-lib/MSchema"

const schema = MSchema.DateTime.check(MSchema.isLessThanDateTime(MDateTime.fromTimestampOrThrow(0)))

// Passes
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(-1))
// Throws a `SchemaError`: Expected a value less than 1970-01-01T00:00:00.000+00:00
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(0))

See

  • isLessThanOrEqualToDateTime — inclusive version

Signature

declare const isLessThanDateTime: (
  exclusiveMaximum: MDateTime.Type,
  annotations?: Schema.Annotations.Filter
) => Filter<MDateTime.Type>

Source

isLessThanOrEqualToDateTime

A filter that checks that a MDateTime is earlier than or equal to a given MDateTime

  • Compares timestamps: the zone offset is ignored.
  • Fails with the message Expected a value less than or equal to <bound>.

Example (Checking that a MDateTime is not after the epoch)

import { Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MSchema from "@parischap/effect-lib/MSchema"

const schema = MSchema.DateTime.check(MSchema.isLessThanOrEqualToDateTime(MDateTime.fromTimestampOrThrow(0)))

// Passes
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(0))
// Throws a `SchemaError`: Expected a value less than or equal to 1970-01-01T00:00:00.000+00:00
Schema.decodeUnknownSync(schema)(MDateTime.fromTimestampOrThrow(1))

See

  • isLessThanDateTime — exclusive version

Signature

declare const isLessThanOrEqualToDateTime: (
  maximum: MDateTime.Type,
  annotations?: Schema.Annotations.Filter
) => Filter<MDateTime.Type>

Source

Instances

DateTime

A Schema that represents a MDateTime

  • Its encoded side (serialization) is an object { timestamp, zoneOffset }.
  • Errors refer to it as MDateTime.
  • Arbitrary generates MDateTime’s between years 1900 and 2100 with integer zone offsets.

Example (Serializing a MDateTime to JSON)

import { Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MSchema from "@parischap/effect-lib/MSchema"

const jsonCodec = Schema.toCodecJson(MSchema.DateTime)

// { timestamp: 0, zoneOffset: 2 }
console.log(Schema.encodeSync(jsonCodec)(MDateTime.fromTimestampOrThrow(0, 2)))

Signature

declare const DateTime: Schema.Codec<MDateTime.Type, MDateTime.Type, never, never>

Source

Utils

BigDecimalFromString

A Schema that transforms a string into a BigDecimal according to format. Read documentation of module NumberBase10Format.ts for more details

  • Decoding fails if the string does not respect format.

Example (Parsing and formatting a French-style BigDecimal)

import { BigDecimal, Schema } from "effect"
import * as MNumberBase10Format from "@parischap/effect-lib/MNumberBase10Format"
import * as MSchema from "@parischap/effect-lib/MSchema"

const schema = MSchema.BigDecimalFromString(MNumberBase10Format.frenchStyleNumber)

// BigDecimal(1024.56)
console.log(Schema.decodeUnknownSync(schema)("1 024,56"))
// '1 024,56'
console.log(Schema.encodeSync(schema)(BigDecimal.make(102_456n, 2)))

Signature

declare const BigDecimalFromString: (format: MNumberBase10Format.Type) => Schema.Codec<BigDecimal.BigDecimal, string>

Source

DateFromDateTime

A Schema that transforms a MDateTime into a Javascript Date. Upon encoding, the MDateTime object is created with the default timeZoneOffset of the machine this code is running on

Example (Converting a MDateTime into a Date)

import { Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MSchema from "@parischap/effect-lib/MSchema"

// 0
console.log(Schema.decodeUnknownSync(MSchema.DateFromDateTime)(MDateTime.fromTimestampOrThrow(0)).getTime())

Signature

declare const DateFromDateTime: Schema.Codec<Date, MDateTime.Type, never, never>

Source

DateFromString

A Schema that transforms a string into a Javascript Date according to the given dateTimeFormat and dateTimeContext. Read documentation of module DateTime.ts for more details.

  • Same as DateTimeFromString followed by DateFromDateTime.

Signature

declare const DateFromString: (
  dateTimeFormat: MDateTimeFormat.Type,
  dateTimeContext: MDateTimeContext.Type
) => Schema.Codec<Date, string>

Source

DateTimeFromString

A Schema that transforms a string into a MDateTime according to the given dateTimeFormat and dateTimeContext. Read documentation of module DateTime.ts for more details.

  • Decoding fails, with the reason in the error message, if the string does not respect dateTimeFormat.
  • Encoding fails if the MDateTime cannot be formatted according to dateTimeFormat.

Example (Parsing a French-style date)

import { Schema } from "effect"
import * as MDateTimeContext from "@parischap/effect-lib/MDateTimeContext"
import * as MDateTimeFormat from "@parischap/effect-lib/MDateTimeFormat"
import * as MSchema from "@parischap/effect-lib/MSchema"

const { Token } = MDateTimeFormat
const format = MDateTimeFormat.make(Token.dd, "/", Token.MM, "/", Token.yyyy)
const schema = MSchema.DateTimeFromString(format, MDateTimeContext.fromLocaleOrThrow("fr-FR"))

// A `MDateTime` for 25 August 2025
console.log(Schema.decodeUnknownSync(schema)("25/08/2025"))

Signature

declare const DateTimeFromString: (
  dateTimeFormat: MDateTimeFormat.Type,
  dateTimeContext: MDateTimeContext.Type
) => Schema.Codec<MDateTime.Type, string>

Source

DateTimeZonedFromDateTime

A Schema that transforms a MDateTime into an effect/DateTime.Zoned. Both objects share the same time zone offset

Example (Converting a MDateTime into an effect/DateTime.Zoned)

import { DateTime, Schema } from "effect"
import * as MDateTime from "@parischap/effect-lib/MDateTime"
import * as MSchema from "@parischap/effect-lib/MSchema"

// 0
console.log(
  DateTime.toEpochMillis(
    Schema.decodeUnknownSync(MSchema.DateTimeZonedFromDateTime)(MDateTime.fromTimestampOrThrow(0, 8))
  )
)

Signature

declare const DateTimeZonedFromDateTime: Schema.Codec<DateTime.Zoned, MDateTime.Type, never, never>

Source

DateTimeZonedFromString

A Schema that transforms a string into an effect/DateTime.Zoned according to the given dateTimeFormat and dateTimeContext. Read documentation of module DateTime.ts for more details.

  • Same as DateTimeFromString followed by DateTimeZonedFromDateTime.

Signature

declare const DateTimeZonedFromString: (
  dateTimeFormat: MDateTimeFormat.Type,
  dateTimeContext: MDateTimeContext.Type
) => Schema.Codec<DateTime.Zoned, string>

Source

FiniteFromString

A Schema that transforms a string into a number according to format. Read documentation of module NumberBase10Format.ts for more details

  • Decoding fails if the string does not respect format.
  • Encoding fails if the number cannot be formatted according to format.

Example (Parsing and formatting a French-style number)

import { Schema } from "effect"
import * as MNumberBase10Format from "@parischap/effect-lib/MNumberBase10Format"
import * as MSchema from "@parischap/effect-lib/MSchema"

const schema = MSchema.FiniteFromString(MNumberBase10Format.frenchStyleNumber)

// 1024.56
console.log(Schema.decodeUnknownSync(schema)("1 024,56"))
// '1 024,56'
console.log(Schema.encodeSync(schema)(1024.56))

Signature

declare const FiniteFromString: (format: MNumberBase10Format.Type) => Schema.Codec<number, string>

Source

Template

A Schema that transforms a string into an object according to template. Read documentation of module Template.ts for more details

  • Decoding fails, with the reason in the error message, if the string does not match template.
  • Encoding fails if the object cannot be formatted according to template.

Example (Parsing a sentence)

import { Schema } from "effect"
import * as MNumberBase10Format from "@parischap/effect-lib/MNumberBase10Format"
import * as MRegExpString from "@parischap/effect-lib/MRegExpString"
import * as MSchema from "@parischap/effect-lib/MSchema"
import * as MTemplate from "@parischap/effect-lib/MTemplate"
import * as MTemplatePlaceholder from "@parischap/effect-lib/MTemplatePlaceholder"
import * as MTemplateSeparator from "@parischap/effect-lib/MTemplateSeparator"

const ph = MTemplatePlaceholder
const sep = MTemplateSeparator

// "#name is a #age-year old #kind."
const template = MTemplate.make(
  ph.anythingBut({ name: "name", forbiddenChars: [MRegExpString.space] }),
  sep.make(" is a "),
  ph.number({ name: "age", numberBase10Format: MNumberBase10Format.unsignedInteger }),
  sep.make("-year old "),
  ph.anythingBut({ name: "kind", forbiddenChars: ["."] }),
  sep.dot
)

// { name: 'Jon', age: 24, kind: 'dog' }
console.log(Schema.decodeUnknownSync(MSchema.Template(template))("Jon is a 24-year old dog."))

Signature

declare const Template: <PlaceholderTypes extends MTypes.Object>(
  template: MTemplate.Type<PlaceholderTypes>
) => Schema.Codec<PlaceholderTypes, string>

Source