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. DateTimeis theSchemaof aMDateTime. Its encoded side is an object{ timestamp, zoneOffset }, so that aMDateTimecan be serialized (JSON…) and generated for property-based testing (Arbitrary), e.g. when it is a field of aMSchemaDataclass.- The filters (
isBetweenDateTime…) check that aMDateTimeis ordered with respect to given bounds. They are built with theSchema.makeIs*functions fromMDateTime.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
MDateTimecompare timestamps and ignore the zone offset. Their bounds do not helpArbitraryto 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— theOrderthe 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
exclusiveMinimumorexclusiveMaximumistrue. - 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>
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>
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>
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>
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>
Instances
DateTime
A Schema that represents a MDateTime
- Its encoded side (serialization) is an object
{ timestamp, zoneOffset }. - Errors refer to it as
MDateTime. ArbitrarygeneratesMDateTime’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>
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>
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>
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
DateTimeFromStringfollowed byDateFromDateTime.
Signature
declare const DateFromString: (
dateTimeFormat: MDateTimeFormat.Type,
dateTimeContext: MDateTimeContext.Type
) => Schema.Codec<Date, string>
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
MDateTimecannot be formatted according todateTimeFormat.
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>
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>
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
DateTimeFromStringfollowed byDateTimeZonedFromDateTime.
Signature
declare const DateTimeZonedFromString: (
dateTimeFormat: MDateTimeFormat.Type,
dateTimeContext: MDateTimeContext.Type
) => Schema.Codec<DateTime.Zoned, string>
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>
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>