Effect Data Types
On this page
Interop With Data
The Data module in the Effect ecosystem serves as a utility module that simplifies the process of comparing values for equality without the need for explicit implementations of the Equal and Hash traits. It provides convenient APIs that automatically generate default implementations for equality checks, making it easier for developers to perform equality comparisons in their applications:
ts
import {Data ,Equal } from "effect"constperson1 =Data .struct ({name : "Alice",age : 30 })constperson2 =Data .struct ({name : "Alice",age : 30 })console .log (Equal .equals (person1 ,person2 )) // true
ts
import {Data ,Equal } from "effect"constperson1 =Data .struct ({name : "Alice",age : 30 })constperson2 =Data .struct ({name : "Alice",age : 30 })console .log (Equal .equals (person1 ,person2 )) // true
You can use the Schema.Data(schema)
combinator to build a schema from an existing schema that can decode a value A
to a value with Equal and Hash traits added:
ts
import {Schema } from "@effect/schema"import {Equal } from "effect"constschema =Schema .Data (Schema .Struct ({name :Schema .String ,age :Schema .Number }))constdecode =Schema .decode (schema )constperson1 =decode ({name : "Alice",age : 30 })constperson2 =decode ({name : "Alice",age : 30 })console .log (Equal .equals (person1 ,person2 )) // true
ts
import {Schema } from "@effect/schema"import {Equal } from "effect"constschema =Schema .Data (Schema .Struct ({name :Schema .String ,age :Schema .Number }))constdecode =Schema .decode (schema )constperson1 =decode ({name : "Alice",age : 30 })constperson2 =decode ({name : "Alice",age : 30 })console .log (Equal .equals (person1 ,person2 )) // true
Config
The Schema.Config
function is specifically designed to enhance configuration validation in software applications.
This feature empowers developers to integrate structured schema validation with configuration settings, ensuring that the configuration data is consistent with predefined schemas and providing detailed feedback when discrepancies are found.
The Schema.Config
function is defined as follows:
ts
Config: <A>(name: string, schema: Schema<A, string>) => Config<A>
ts
Config: <A>(name: string, schema: Schema<A, string>) => Config<A>
This function requires two parameters:
- name: The identifier for the configuration setting.
- schema: A schema object that describes the expected data type and structure.
The function returns a Config object that is directly integrated with your application's configuration management system.
The Schema.Config
function operates through the following steps:
- Fetching Configuration: The configuration value is retrieved based on its name.
- Validation: The value is then validated against the schema. If the value does not conform to the schema, the function formats and returns detailed validation errors.
- Error Formatting: Errors are formatted using
TreeFormatter.formatErrorSync
to provide clear, actionable error messages.
Example
ts
import {Schema } from "@effect/schema"import {Effect } from "effect"constmyconfig =Schema .Config ("Foo",Schema .String .pipe (Schema .minLength (4)))constprogram =Effect .gen (function* () {constfoo = yield*myconfig console .log (`ok: ${foo }`)})Effect .runSync (program )
ts
import {Schema } from "@effect/schema"import {Effect } from "effect"constmyconfig =Schema .Config ("Foo",Schema .String .pipe (Schema .minLength (4)))constprogram =Effect .gen (function* () {constfoo = yield*myconfig console .log (`ok: ${foo }`)})Effect .runSync (program )
To test the configuration, execute the following commands:
- Test with Missing Configuration Data:
shnpx tsx config.ts# Output:# [(Missing data at Foo: "Expected Foo to exist in the process context")]shnpx tsx config.ts# Output:# [(Missing data at Foo: "Expected Foo to exist in the process context")]
- Test with Invalid Data:
shFoo=bar npx tsx config.ts# Output:# [(Invalid data at Foo: "a string at least 4 character(s) long# └─ Predicate refinement failure# └─ Expected a string at least 4 character(s) long, actual "bar"")]shFoo=bar npx tsx config.ts# Output:# [(Invalid data at Foo: "a string at least 4 character(s) long# └─ Predicate refinement failure# └─ Expected a string at least 4 character(s) long, actual "bar"")]
- Test with Valid Data:
shFoo=foobar npx tsx config.ts# Output:# ok: foobarshFoo=foobar npx tsx config.ts# Output:# ok: foobar
Option
Option
- Decoding
{ _tag: "None" }
is converted toOption.none()
.{ _tag: "Some", value: i }
is converted toOption.some(a)
, wherei
is decoded intoa
using the inner schema.
- Encoding
Option.none()
is converted to{ _tag: "None" }
.Option.some(a)
is converted to{ _tag: "Some", value: i }
, wherea
is encoded intoi
using the inner schema.
Example
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .Option (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ({_tag : "None" })) // { _id: 'Option', _tag: 'None' }console .log (decode ({_tag : "Some",value : "1" })) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // { _tag: 'None' }console .log (encode (Option .some (1))) // { _tag: 'Some', value: '1' }
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .Option (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ({_tag : "None" })) // { _id: 'Option', _tag: 'None' }console .log (decode ({_tag : "Some",value : "1" })) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // { _tag: 'None' }console .log (encode (Option .some (1))) // { _tag: 'Some', value: '1' }
OptionFromSelf
- Decoding
Option.none()
remains asOption.none()
.Option.some(i)
is converted toOption.some(a)
, wherei
is decoded intoa
using the inner schema.
- Encoding
Option.none()
remains asOption.none()
.Option.some(a)
is converted toOption.some(i)
, wherea
is encoded intoi
using the inner schema.
Example
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .OptionFromSelf (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (Option .none ())) // { _id: 'Option', _tag: 'None' }console .log (decode (Option .some ("1"))) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // { _id: 'Option', _tag: 'None' }console .log (encode (Option .some (1))) // { _id: 'Option', _tag: 'Some', value: '1' }
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .OptionFromSelf (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (Option .none ())) // { _id: 'Option', _tag: 'None' }console .log (decode (Option .some ("1"))) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // { _id: 'Option', _tag: 'None' }console .log (encode (Option .some (1))) // { _id: 'Option', _tag: 'Some', value: '1' }
OptionFromUndefinedOr
- Decoding
undefined
is converted toOption.none()
.i
is converted toOption.some(a)
, wherei
is decoded intoa
using the inner schema.
- Encoding
Option.none()
is converted toundefined
.Option.some(a)
is converted toi
, wherea
is encoded intoi
using the inner schema.
Example
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .OptionFromUndefinedOr (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (undefined )) // { _id: 'Option', _tag: 'None' }console .log (decode ("1")) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // undefinedconsole .log (encode (Option .some (1))) // "1"
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .OptionFromUndefinedOr (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (undefined )) // { _id: 'Option', _tag: 'None' }console .log (decode ("1")) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // undefinedconsole .log (encode (Option .some (1))) // "1"
OptionFromNullOr
- Decoding
null
is converted toOption.none()
.i
is converted toOption.some(a)
, wherei
is decoded intoa
using the inner schema.
- Encoding
Option.none()
is converted tonull
.Option.some(a)
is converted toi
, wherea
is encoded intoi
using the inner schema.
Example
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .OptionFromNullOr (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (null)) // { _id: 'Option', _tag: 'None' }console .log (decode ("1")) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // nullconsole .log (encode (Option .some (1))) // "1"
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .OptionFromNullOr (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (null)) // { _id: 'Option', _tag: 'None' }console .log (decode ("1")) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // nullconsole .log (encode (Option .some (1))) // "1"
OptionFromNullishOr
- Decoding
null
is converted toOption.none()
.undefined
is converted toOption.none()
.i
is converted toOption.some(a)
, wherei
is decoded intoa
using the inner schema.
- Encoding
Option.none()
is converted to a specified value (undefined
ornull
based on user choice).Option.some(a)
is converted toi
, wherea
is encoded intoi
using the inner schema.
Example
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .OptionFromNullishOr (Schema .NumberFromString ,undefined )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (null)) // { _id: 'Option', _tag: 'None' }console .log (decode (undefined )) // { _id: 'Option', _tag: 'None' }console .log (decode ("1")) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // undefinedconsole .log (encode (Option .some (1))) // "1"
ts
import {Schema } from "@effect/schema"import {Option } from "effect"constschema =Schema .OptionFromNullishOr (Schema .NumberFromString ,undefined )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (null)) // { _id: 'Option', _tag: 'None' }console .log (decode (undefined )) // { _id: 'Option', _tag: 'None' }console .log (decode ("1")) // { _id: 'Option', _tag: 'Some', value: 1 }console .log (encode (Option .none ())) // undefinedconsole .log (encode (Option .some (1))) // "1"
OptionFromNonEmptyTrimmedString
- Decoding
s
is converted toOption.some(s)
, ifs.trim().length > 0
.Option.none()
otherwise.
- Encoding
Option.none()
is converted to""
.Option.some(s)
is converted tos
.
Example
ts
import {Schema } from "@effect/schema"console .log (Schema .decodeSync (Schema .OptionFromNonEmptyTrimmedString )("")) // Option.none()console .log (Schema .decodeSync (Schema .OptionFromNonEmptyTrimmedString )(" a ")) // Option.some("a")console .log (Schema .decodeSync (Schema .OptionFromNonEmptyTrimmedString )("a")) // Option.some("a")
ts
import {Schema } from "@effect/schema"console .log (Schema .decodeSync (Schema .OptionFromNonEmptyTrimmedString )("")) // Option.none()console .log (Schema .decodeSync (Schema .OptionFromNonEmptyTrimmedString )(" a ")) // Option.some("a")console .log (Schema .decodeSync (Schema .OptionFromNonEmptyTrimmedString )("a")) // Option.some("a")
Either
Either
- Decoding
{ _tag: "Left", left: li }
->Either.left(la)
{ _tag: "Right", right: ri }
->Either.right(ra)
- Encoding
Either.left(la)
->{ _tag: "Left", left: li }
Either.right(ra)
->{ _tag: "Right", right: ri }
Example
ts
import {Schema } from "@effect/schema"import {Either } from "effect"constschema =Schema .Either ({left :Schema .Trim ,right :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ({_tag : "Left",left : " a " })) // { _id: 'Either', _tag: 'Left', left: 'a' }console .log (decode ({_tag : "Right",right : "1" })) // { _id: 'Either', _tag: 'Right', right: 1 }console .log (encode (Either .left ("a"))) // { _tag: 'Left', left: 'a' }console .log (encode (Either .right (1))) // { _tag: 'Right', right: '1' }
ts
import {Schema } from "@effect/schema"import {Either } from "effect"constschema =Schema .Either ({left :Schema .Trim ,right :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ({_tag : "Left",left : " a " })) // { _id: 'Either', _tag: 'Left', left: 'a' }console .log (decode ({_tag : "Right",right : "1" })) // { _id: 'Either', _tag: 'Right', right: 1 }console .log (encode (Either .left ("a"))) // { _tag: 'Left', left: 'a' }console .log (encode (Either .right (1))) // { _tag: 'Right', right: '1' }
EitherFromSelf
- Decoding
Either.left(li)
->Either.left(la)
Either.right(ri)
->Either.right(ra)
- Encoding
Either.left(la)
->Either.left(li)
Either.right(ra)
->Either.right(ri)
Example
ts
import {Schema } from "@effect/schema"import {Either } from "effect"constschema =Schema .EitherFromSelf ({left :Schema .Trim ,right :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (Either .left (" a "))) // { _id: 'Either', _tag: 'Left', left: 'a' }console .log (decode (Either .right ("1"))) // { _id: 'Either', _tag: 'Right', right: 1 }console .log (encode (Either .left ("a"))) // { _id: 'Either', _tag: 'Left', left: 'a' }console .log (encode (Either .right (1))) // { _id: 'Either', _tag: 'Right', right: '1' }
ts
import {Schema } from "@effect/schema"import {Either } from "effect"constschema =Schema .EitherFromSelf ({left :Schema .Trim ,right :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (Either .left (" a "))) // { _id: 'Either', _tag: 'Left', left: 'a' }console .log (decode (Either .right ("1"))) // { _id: 'Either', _tag: 'Right', right: 1 }console .log (encode (Either .left ("a"))) // { _id: 'Either', _tag: 'Left', left: 'a' }console .log (encode (Either .right (1))) // { _id: 'Either', _tag: 'Right', right: '1' }
EitherFromUnion
- Decoding
li
->Either.left(la)
ri
->Either.right(ra)
- Encoding
Either.left(la)
->li
Either.right(ra)
->ri
Example
ts
import {Schema } from "@effect/schema"import {Either } from "effect"constschema =Schema .EitherFromUnion ({left :Schema .Boolean ,right :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (true)) // { _id: 'Either', _tag: 'Left', left: true }console .log (decode ("1")) // { _id: 'Either', _tag: 'Right', right: 1 }console .log (encode (Either .left (true))) // trueconsole .log (encode (Either .right (1))) // "1"
ts
import {Schema } from "@effect/schema"import {Either } from "effect"constschema =Schema .EitherFromUnion ({left :Schema .Boolean ,right :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (true)) // { _id: 'Either', _tag: 'Left', left: true }console .log (decode ("1")) // { _id: 'Either', _tag: 'Right', right: 1 }console .log (encode (Either .left (true))) // trueconsole .log (encode (Either .right (1))) // "1"
ReadonlySet
ReadonlySet
- Decoding
ReadonlyArray<I>
->ReadonlySet<A>
- Encoding
ReadonlySet<A>
->ReadonlyArray<I>
Example
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlySet (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (["1", "2", "3"])) // Set(3) { 1, 2, 3 }console .log (encode (newSet ([1, 2, 3]))) // [ '1', '2', '3' ]
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlySet (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (["1", "2", "3"])) // Set(3) { 1, 2, 3 }console .log (encode (newSet ([1, 2, 3]))) // [ '1', '2', '3' ]
ReadonlySetFromSelf
- Decoding
ReadonlySet<I>
->ReadonlySet<A>
- Encoding
ReadonlySet<A>
->ReadonlySet<I>
Example
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlySetFromSelf (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (newSet (["1", "2", "3"]))) // Set(3) { 1, 2, 3 }console .log (encode (newSet ([1, 2, 3]))) // Set(3) { '1', '2', '3' }
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlySetFromSelf (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (newSet (["1", "2", "3"]))) // Set(3) { 1, 2, 3 }console .log (encode (newSet ([1, 2, 3]))) // Set(3) { '1', '2', '3' }
ReadonlyMap
ReadonlyMap
- Decoding
ReadonlyArray<readonly [KI, VI]>
->ReadonlyMap<KA, VA>
- Encoding
ReadonlyMap<KA, VA>
->ReadonlyArray<readonly [KI, VI]>
Example
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlyMap ({key :Schema .String ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ([["a", "2"],["b", "2"],["c", "3"]])) // Map(3) { 'a' => 2, 'b' => 2, 'c' => 3 }console .log (encode (newMap ([["a", 1],["b", 2],["c", 3]]))) // [ [ 'a', '1' ], [ 'b', '2' ], [ 'c', '3' ] ]
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlyMap ({key :Schema .String ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ([["a", "2"],["b", "2"],["c", "3"]])) // Map(3) { 'a' => 2, 'b' => 2, 'c' => 3 }console .log (encode (newMap ([["a", 1],["b", 2],["c", 3]]))) // [ [ 'a', '1' ], [ 'b', '2' ], [ 'c', '3' ] ]
ReadonlyMapFromSelf
- Decoding
ReadonlyMap<KI, VI>
->ReadonlyMap<KA, VA>
- Encoding
ReadonlyMap<KA, VA>
->ReadonlyMap<KI, VI>
Example
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlyMapFromSelf ({key :Schema .String ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (newMap ([["a", "2"],["b", "2"],["c", "3"]]))) // Map(3) { 'a' => 2, 'b' => 2, 'c' => 3 }console .log (encode (newMap ([["a", 1],["b", 2],["c", 3]]))) // Map(3) { 'a' => '1', 'b' => '2', 'c' => '3' }
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlyMapFromSelf ({key :Schema .String ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (newMap ([["a", "2"],["b", "2"],["c", "3"]]))) // Map(3) { 'a' => 2, 'b' => 2, 'c' => 3 }console .log (encode (newMap ([["a", 1],["b", 2],["c", 3]]))) // Map(3) { 'a' => '1', 'b' => '2', 'c' => '3' }
ReadonlyMapFromRecord
- Decoding
{ readonly [x: string]: VI }
->ReadonlyMap<KA, VA>
- Encoding
ReadonlyMap<KA, VA>
->{ readonly [x: string]: VI }
Example
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlyMapFromRecord ({key :Schema .NumberFromString ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ({"1": "4","2": "5","3": "6"})) // Map(3) { 1 => 4, 2 => 5, 3 => 6 }console .log (encode (newMap ([[1, 4],[2, 5],[3, 6]]))) // { '1': '4', '2': '5', '3': '6' }
ts
import {Schema } from "@effect/schema"constschema =Schema .ReadonlyMapFromRecord ({key :Schema .NumberFromString ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ({"1": "4","2": "5","3": "6"})) // Map(3) { 1 => 4, 2 => 5, 3 => 6 }console .log (encode (newMap ([[1, 4],[2, 5],[3, 6]]))) // { '1': '4', '2': '5', '3': '6' }
HashSet
HashSet
- Decoding
ReadonlyArray<I>
->HashSet<A>
- Encoding
HashSet<A>
->ReadonlyArray<I>
Example
ts
import {Schema } from "@effect/schema"import {HashSet } from "effect"constschema =Schema .HashSet (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (["1", "2", "3"])) // { _id: 'HashSet', values: [ 1, 2, 3 ] }console .log (encode (HashSet .fromIterable ([1, 2, 3]))) // [ '1', '2', '3' ]
ts
import {Schema } from "@effect/schema"import {HashSet } from "effect"constschema =Schema .HashSet (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (["1", "2", "3"])) // { _id: 'HashSet', values: [ 1, 2, 3 ] }console .log (encode (HashSet .fromIterable ([1, 2, 3]))) // [ '1', '2', '3' ]
HashSetFromSelf
- Decoding
HashSet<I>
->HashSet<A>
- Encoding
HashSet<A>
->HashSet<I>
Example
ts
import {Schema } from "@effect/schema"import {HashSet } from "effect"constschema =Schema .HashSetFromSelf (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (HashSet .fromIterable (["1", "2", "3"]))) // { _id: 'HashSet', values: [ 1, 2, 3 ] }console .log (encode (HashSet .fromIterable ([1, 2, 3]))) // { _id: 'HashSet', values: [ '1', '3', '2' ] }
ts
import {Schema } from "@effect/schema"import {HashSet } from "effect"constschema =Schema .HashSetFromSelf (Schema .NumberFromString )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (HashSet .fromIterable (["1", "2", "3"]))) // { _id: 'HashSet', values: [ 1, 2, 3 ] }console .log (encode (HashSet .fromIterable ([1, 2, 3]))) // { _id: 'HashSet', values: [ '1', '3', '2' ] }
HashMap
HashMap
- Decoding
ReadonlyArray<readonly [KI, VI]>
->HashMap<KA, VA>
- Encoding
HashMap<KA, VA>
->ReadonlyArray<readonly [KI, VI]>
Example
ts
import {Schema } from "@effect/schema"import {HashMap } from "effect"constschema =Schema .HashMap ({key :Schema .String ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ([["a", "2"],["b", "2"],["c", "3"]])) // { _id: 'HashMap', values: [ [ 'a', 2 ], [ 'c', 3 ], [ 'b', 2 ] ] }console .log (encode (HashMap .fromIterable ([["a", 1],["b", 2],["c", 3]]))) // [ [ 'a', '1' ], [ 'c', '3' ], [ 'b', '2' ] ]
ts
import {Schema } from "@effect/schema"import {HashMap } from "effect"constschema =Schema .HashMap ({key :Schema .String ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode ([["a", "2"],["b", "2"],["c", "3"]])) // { _id: 'HashMap', values: [ [ 'a', 2 ], [ 'c', 3 ], [ 'b', 2 ] ] }console .log (encode (HashMap .fromIterable ([["a", 1],["b", 2],["c", 3]]))) // [ [ 'a', '1' ], [ 'c', '3' ], [ 'b', '2' ] ]
HashMapFromSelf
- Decoding
HashMap<KI, VI>
->HashMap<KA, VA>
- Encoding
HashMap<KA, VA>
->HashMap<KI, VI>
Example
ts
import {Schema } from "@effect/schema"import {HashMap } from "effect"constschema =Schema .HashMapFromSelf ({key :Schema .String ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (HashMap .fromIterable ([["a", "2"],["b", "2"],["c", "3"]]))) // { _id: 'HashMap', values: [ [ 'a', 2 ], [ 'c', 3 ], [ 'b', 2 ] ] }console .log (encode (HashMap .fromIterable ([["a", 1],["b", 2],["c", 3]]))) // { _id: 'HashMap', values: [ [ 'a', '1' ], [ 'c', '3' ], [ 'b', '2' ] ] }
ts
import {Schema } from "@effect/schema"import {HashMap } from "effect"constschema =Schema .HashMapFromSelf ({key :Schema .String ,value :Schema .NumberFromString })constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (HashMap .fromIterable ([["a", "2"],["b", "2"],["c", "3"]]))) // { _id: 'HashMap', values: [ [ 'a', 2 ], [ 'c', 3 ], [ 'b', 2 ] ] }console .log (encode (HashMap .fromIterable ([["a", 1],["b", 2],["c", 3]]))) // { _id: 'HashMap', values: [ [ 'a', '1' ], [ 'c', '3' ], [ 'b', '2' ] ] }
SortedSet
SortedSet
- Decoding
ReadonlyArray<I>
->SortedSet<A>
- Encoding
SortedSet<A>
->ReadonlyArray<I>
Example
ts
import {Schema } from "@effect/schema"import {Number ,SortedSet } from "effect"constschema =Schema .SortedSet (Schema .NumberFromString ,Number .Order )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (["1", "2", "3"])) // { _id: 'SortedSet', values: [ 1, 2, 3 ] }console .log (encode (SortedSet .fromIterable (Number .Order )([1, 2, 3]))) // [ '1', '2', '3' ]
ts
import {Schema } from "@effect/schema"import {Number ,SortedSet } from "effect"constschema =Schema .SortedSet (Schema .NumberFromString ,Number .Order )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (["1", "2", "3"])) // { _id: 'SortedSet', values: [ 1, 2, 3 ] }console .log (encode (SortedSet .fromIterable (Number .Order )([1, 2, 3]))) // [ '1', '2', '3' ]
SortedSetFromSelf
- Decoding
SortedSet<I>
->SortedSet<A>
- Encoding
SortedSet<A>
->SortedSet<I>
Example
ts
import {Schema } from "@effect/schema"import {Number ,SortedSet ,String } from "effect"constschema =Schema .SortedSetFromSelf (Schema .NumberFromString ,Number .Order ,String .Order )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (SortedSet .fromIterable (String .Order )(["1", "2", "3"]))) // { _id: 'SortedSet', values: [ 1, 2, 3 ] }console .log (encode (SortedSet .fromIterable (Number .Order )([1, 2, 3]))) // { _id: 'SortedSet', values: [ '1', '2', '3' ] }
ts
import {Schema } from "@effect/schema"import {Number ,SortedSet ,String } from "effect"constschema =Schema .SortedSetFromSelf (Schema .NumberFromString ,Number .Order ,String .Order )constdecode =Schema .decodeUnknownSync (schema )constencode =Schema .encodeSync (schema )console .log (decode (SortedSet .fromIterable (String .Order )(["1", "2", "3"]))) // { _id: 'SortedSet', values: [ 1, 2, 3 ] }console .log (encode (SortedSet .fromIterable (Number .Order )([1, 2, 3]))) // { _id: 'SortedSet', values: [ '1', '2', '3' ] }
Duration
Duration
Converts an hrtime(i.e. [seconds: number, nanos: number]
) into a Duration
.
Example
ts
import {Schema } from "@effect/schema"constschema =Schema .Duration // Schema<Duration, number>constdecode =Schema .decodeUnknownSync (schema )console .log (decode ([0, 0])) // { _id: 'Duration', _tag: 'Millis', millis: 0 }console .log (decode ([5000, 0])) // { _id: 'Duration', _tag: 'Nanos', hrtime: [ 5000, 0 ] }
ts
import {Schema } from "@effect/schema"constschema =Schema .Duration // Schema<Duration, number>constdecode =Schema .decodeUnknownSync (schema )console .log (decode ([0, 0])) // { _id: 'Duration', _tag: 'Millis', millis: 0 }console .log (decode ([5000, 0])) // { _id: 'Duration', _tag: 'Nanos', hrtime: [ 5000, 0 ] }
DurationFromSelf
The DurationFromSelf
schema is designed to validate that a given value conforms to the Duration
type from the effect
library.
Example
ts
import {Schema } from "@effect/schema"import {Duration } from "effect"constschema =Schema .DurationFromSelf constdecode =Schema .decodeUnknownSync (schema )console .log (decode (Duration .seconds (2))) // { _id: 'Duration', _tag: 'Millis', millis: 2000 }console .log (decode (null)) // throws ParseError: Expected DurationFromSelf, actual null
ts
import {Schema } from "@effect/schema"import {Duration } from "effect"constschema =Schema .DurationFromSelf constdecode =Schema .decodeUnknownSync (schema )console .log (decode (Duration .seconds (2))) // { _id: 'Duration', _tag: 'Millis', millis: 2000 }console .log (decode (null)) // throws ParseError: Expected DurationFromSelf, actual null
DurationFromMillis
Converts a number
into a Duration
where the number represents the number of milliseconds.
Example
ts
import {Schema } from "@effect/schema"constschema =Schema .DurationFromMillis // Schema<Duration, number>constdecode =Schema .decodeUnknownSync (schema )console .log (decode (0)) // { _id: 'Duration', _tag: 'Millis', millis: 0 }console .log (decode (5000)) // { _id: 'Duration', _tag: 'Millis', millis: 5000 }
ts
import {Schema } from "@effect/schema"constschema =Schema .DurationFromMillis // Schema<Duration, number>constdecode =Schema .decodeUnknownSync (schema )console .log (decode (0)) // { _id: 'Duration', _tag: 'Millis', millis: 0 }console .log (decode (5000)) // { _id: 'Duration', _tag: 'Millis', millis: 5000 }
DurationFromNanos
Converts a BigInt
into a Duration
where the number represents the number of nanoseconds.
Example
ts
import {Schema } from "@effect/schema"constschema =Schema .DurationFromNanos // Schema<Duration, BigInt>constdecode =Schema .decodeUnknownSync (schema )console .log (decode (0n)) // { _id: 'Duration', _tag: 'Millis', millis: 0 }console .log (decode (5000000000n)) // { _id: 'Duration', _tag: 'Nanos', hrtime: [ 5, 0 ] }
ts
import {Schema } from "@effect/schema"constschema =Schema .DurationFromNanos // Schema<Duration, BigInt>constdecode =Schema .decodeUnknownSync (schema )console .log (decode (0n)) // { _id: 'Duration', _tag: 'Millis', millis: 0 }console .log (decode (5000000000n)) // { _id: 'Duration', _tag: 'Nanos', hrtime: [ 5, 0 ] }
clampDuration
Clamps a Duration
between a minimum and a maximum value.
Example
ts
import {Schema } from "@effect/schema"import {Duration } from "effect"constschema =Schema .DurationFromSelf .pipe (Schema .clampDuration ("5 seconds", "10 seconds"))constdecode =Schema .decodeUnknownSync (schema )console .log (decode (Duration .decode ("2 seconds"))) // { _id: 'Duration', _tag: 'Millis', millis: 5000 }console .log (decode (Duration .decode ("6 seconds"))) // { _id: 'Duration', _tag: 'Millis', millis: 6000 }console .log (decode (Duration .decode ("11 seconds"))) // { _id: 'Duration', _tag: 'Millis', millis: 10000 }
ts
import {Schema } from "@effect/schema"import {Duration } from "effect"constschema =Schema .DurationFromSelf .pipe (Schema .clampDuration ("5 seconds", "10 seconds"))constdecode =Schema .decodeUnknownSync (schema )console .log (decode (Duration .decode ("2 seconds"))) // { _id: 'Duration', _tag: 'Millis', millis: 5000 }console .log (decode (Duration .decode ("6 seconds"))) // { _id: 'Duration', _tag: 'Millis', millis: 6000 }console .log (decode (Duration .decode ("11 seconds"))) // { _id: 'Duration', _tag: 'Millis', millis: 10000 }
Redacted
Redacted
The Schema.Redacted
functionis specifically designed to handle sensitive information by converting a string
into a Redacted object.
This transformation ensures that the sensitive data is not exposed in the application's output.
Example
ts
import {Schema } from "@effect/schema"// Schema.Redacted<typeof Schema.String>constschema =Schema .Redacted (Schema .String )constdecode =Schema .decodeUnknownSync (schema )console .log (decode ("keep it secret, keep it safe")) // {}
ts
import {Schema } from "@effect/schema"// Schema.Redacted<typeof Schema.String>constschema =Schema .Redacted (Schema .String )constdecode =Schema .decodeUnknownSync (schema )console .log (decode ("keep it secret, keep it safe")) // {}
It's important to note that when successfully decoding a Redacted
, the output is intentionally obscured ({}
) to prevent the actual secret from being revealed in logs or console outputs.
When composing the Redacted
schema with other schemas, care must be taken
as decoding or encoding errors could potentially expose sensitive
information.
Practical Example Showing Potential Data Exposure
ts
import {Schema } from "@effect/schema"import {Redacted } from "effect"constschema =Schema .Trimmed .pipe (Schema .compose (Schema .Redacted (Schema .String )))console .log (Schema .decodeUnknownEither (schema )(" SECRET"))/*{_id: 'Either',_tag: 'Left',left: {_id: 'ParseError',message: '(Trimmed <-> (string <-> Redacted(<redacted>)))\n' +'└─ Encoded side transformation failure\n' +' └─ Trimmed\n' +' └─ Predicate refinement failure\n' +' └─ Expected Trimmed (a string with no leading or trailing whitespace), actual " SECRET"'}}*/console .log (Schema .encodeEither (schema )(Redacted .make (" SECRET")))/*{_id: 'Either',_tag: 'Left',left: {_id: 'ParseError',message: '(Trimmed <-> (string <-> Redacted(<redacted>)))\n' +'└─ Encoded side transformation failure\n' +' └─ Trimmed\n' +' └─ Predicate refinement failure\n' +' └─ Expected Trimmed (a string with no leading or trailing whitespace), actual " SECRET"'}}*/
ts
import {Schema } from "@effect/schema"import {Redacted } from "effect"constschema =Schema .Trimmed .pipe (Schema .compose (Schema .Redacted (Schema .String )))console .log (Schema .decodeUnknownEither (schema )(" SECRET"))/*{_id: 'Either',_tag: 'Left',left: {_id: 'ParseError',message: '(Trimmed <-> (string <-> Redacted(<redacted>)))\n' +'└─ Encoded side transformation failure\n' +' └─ Trimmed\n' +' └─ Predicate refinement failure\n' +' └─ Expected Trimmed (a string with no leading or trailing whitespace), actual " SECRET"'}}*/console .log (Schema .encodeEither (schema )(Redacted .make (" SECRET")))/*{_id: 'Either',_tag: 'Left',left: {_id: 'ParseError',message: '(Trimmed <-> (string <-> Redacted(<redacted>)))\n' +'└─ Encoded side transformation failure\n' +' └─ Trimmed\n' +' └─ Predicate refinement failure\n' +' └─ Expected Trimmed (a string with no leading or trailing whitespace), actual " SECRET"'}}*/
In the example above, if the input string does not meet the criteria (e.g., contains spaces), the error message generated might inadvertently expose sensitive information included in the input.
Mitigating Exposure Risks
To reduce the risk of sensitive information leakage in error messages, you can customize the error messages to obscure sensitive details:
ts
import {Schema } from "@effect/schema"import {Redacted } from "effect"constschema =Schema .Trimmed .annotations ({message : () => "Expected Trimmed, actual <redacted>"}).pipe (Schema .compose (Schema .Redacted (Schema .String )))console .log (Schema .decodeUnknownEither (schema )(" SECRET"))/*{_id: 'Either',_tag: 'Left',left: {_id: 'ParseError',message: '(Trimmed <-> (string <-> Redacted(<redacted>)))\n' +'└─ Encoded side transformation failure\n' +' └─ Expected Trimmed, actual <redacted>'}}*/console .log (Schema .encodeEither (schema )(Redacted .make (" SECRET")))/*{_id: 'Either',_tag: 'Left',left: {_id: 'ParseError',message: '(Trimmed <-> (string <-> Redacted(<redacted>)))\n' +'└─ Encoded side transformation failure\n' +' └─ Expected Trimmed, actual <redacted>'}}*/
ts
import {Schema } from "@effect/schema"import {Redacted } from "effect"constschema =Schema .Trimmed .annotations ({message : () => "Expected Trimmed, actual <redacted>"}).pipe (Schema .compose (Schema .Redacted (Schema .String )))console .log (Schema .decodeUnknownEither (schema )(" SECRET"))/*{_id: 'Either',_tag: 'Left',left: {_id: 'ParseError',message: '(Trimmed <-> (string <-> Redacted(<redacted>)))\n' +'└─ Encoded side transformation failure\n' +' └─ Expected Trimmed, actual <redacted>'}}*/console .log (Schema .encodeEither (schema )(Redacted .make (" SECRET")))/*{_id: 'Either',_tag: 'Left',left: {_id: 'ParseError',message: '(Trimmed <-> (string <-> Redacted(<redacted>)))\n' +'└─ Encoded side transformation failure\n' +' └─ Expected Trimmed, actual <redacted>'}}*/
RedactedFromSelf
The Schema.RedactedFromSelf
schema is designed to validate that a given value conforms to the Redacted
type from the effect
library.
Example
ts
import {Schema } from "@effect/schema"import {Redacted } from "effect"constschema =Schema .RedactedFromSelf (Schema .String )constdecode =Schema .decodeUnknownSync (schema )console .log (decode (Redacted .make ("mysecret"))) // {}console .log (decode (null)) // throws ParseError: Expected Redacted(<redacted>), actual null
ts
import {Schema } from "@effect/schema"import {Redacted } from "effect"constschema =Schema .RedactedFromSelf (Schema .String )constdecode =Schema .decodeUnknownSync (schema )console .log (decode (Redacted .make ("mysecret"))) // {}console .log (decode (null)) // throws ParseError: Expected Redacted(<redacted>), actual null
It's important to note that when successfully decoding a Redacted
, the output is intentionally obscured ({}
) to prevent the actual secret from being revealed in logs or console outputs.