已发布 上游基线 bf46254 原文 ↗ 在 GitHub 编辑

Effect 数据类型

为 Option、Result、Exit、Effect 集合、Duration、Redacted 值以及配置定义 schema。

Effect 为其运行时数据类型提供了对应的 schema,包括 OptionResultExit、hash 集合、DurationRedacted

这些 schema 要求两侧都是相应的运行时值。它们内部的 schema 仍然可以转换其中包含的值。当你需要一种与 JSON 兼容的表示形式时,可以用 Schema.toCodecJson 派生出来。

示例(运行时值及其 JSON 表示形式)

import { Option, Schema } from "effect"

const RuntimeOption = Schema.Option(Schema.FiniteFromString)

Schema.decodeUnknownSync(RuntimeOption)(Option.some("1")) // => Option.some(1)
Schema.encodeSync(RuntimeOption)(Option.some(1)) // => Option.some("1")

const JsonOption = Schema.toCodecJson(RuntimeOption)

Schema.decodeUnknownSync(JsonOption)({ _tag: "Some", value: "1" }) // => Option.some(1)
Schema.encodeSync(JsonOption)(Option.some(1)) // => { _tag: "Some", value: "1" }

Config

使用 Config.schema 可以通过 schema 读取并解码配置。provider 提供其编码后的表示形式,得到的 Config 则产出该 schema 的 Type

示例(读取结构化配置)

import { Config, ConfigProvider, Effect, Schema } from "effect"

const DatabaseConfig = Config.schema(
  Schema.Struct({
    host: Schema.String,
    port: Schema.Finite,
  }),
  "database",
)

const provider = ConfigProvider.fromUnknown({
  database: {
    host: "localhost",
    port: 5432,
  },
})

Effect.runSync(DatabaseConfig.parse(provider)) // => { host: "localhost", port: 5432 }

关于配置 provider、嵌套、默认值和密钥,请参见配置

Option

Schema.Option(value) 描述 Option 值,并把 value 应用到 Some 的内容上。

示例(转换 Option 的值)

import { Option, Schema } from "effect"

const schema = Schema.Option(Schema.FiniteFromString)

// Option<string> -> Option<number>
Schema.decodeUnknownSync(schema)(Option.some("1")) // => Option.some(1)

// Option<number> -> Option<string>
Schema.encodeSync(schema)(Option.some(1)) // => Option.some("1")

Schema.decodeUnknownSync(schema)(Option.none()) // => Option.none()

从可空值与可选值得到 Option

以下 schema 会把常见的可空(nullable)和可选(optional)表示形式转换为 Option 值:

Schema会被解码为 None 的值None 的默认编码
OptionFromUndefinedOrundefinedundefined
OptionFromNullOrnullnull
OptionFromNullishOrnullundefinedundefined
OptionFromOptionalKey缺失的属性缺失的属性
OptionFromOptional缺失的属性或 undefined缺失的属性
OptionFromOptionalNullOr缺失的属性、nullundefined缺失的属性

OptionFromNullishOr 接受一个取值为 nullundefinedonNoneEncoding 选项。OptionFromOptionalNullOr 接受 "omit"nullundefined

示例(把可选属性映射为 Option)

import { Option, Schema } from "effect"

const Profile = Schema.Struct({
  nickname: Schema.OptionFromOptionalKey(Schema.String),
})

Schema.decodeUnknownSync(Profile)({}) // => { nickname: Option.none() }
Schema.decodeUnknownSync(Profile)({ nickname: "Ada" }) // => { nickname: Option.some("Ada") }

Schema.encodeSync(Profile)({ nickname: Option.none() }) // => {}

示例(把 nullish 值映射为 Option)

import { Option, Schema } from "effect"

const schema = Schema.OptionFromNullishOr(Schema.FiniteFromString, {
  onNoneEncoding: null,
})

Schema.decodeUnknownSync(schema)(undefined) // => Option.none()
Schema.decodeUnknownSync(schema)(null) // => Option.none()
Schema.decodeUnknownSync(schema)("1") // => Option.some(1)

Schema.encodeSync(schema)(Option.none()) // => null

Result

Schema.Result(success, failure) 描述 Result 值,并分别转换成功通道与失败通道。

示例(转换 Result 值)

import { Result, Schema } from "effect"

const schema = Schema.Result(Schema.FiniteFromString, Schema.Trim)

Schema.decodeUnknownSync(schema)(Result.succeed("1")) // => Result.succeed(1)
Schema.decodeUnknownSync(schema)(Result.fail(" error ")) // => Result.fail("error")

Schema.encodeSync(schema)(Result.succeed(1)) // => Result.succeed("1")

其默认的 JSON 表示形式使用 { _tag: "Success", success }{ _tag: "Failure", failure }

示例(Result 的 JSON 形式)

import { Result, Schema } from "effect"

const schema = Schema.toCodecJson(
  Schema.Result(Schema.FiniteFromString, Schema.Trim),
)

Schema.decodeUnknownSync(schema)({ _tag: "Success", success: "1" }) // => Result.succeed(1)
Schema.encodeSync(schema)(Result.fail("error")) // => { _tag: "Failure", failure: "error" }

Exit

Schema.Exit(success, failure, defect) 描述 Exit 值。它把提供的 schema 分别应用到成功值、预期失败和 defect 上。

示例(转换 Exit 值)

import { Exit, Schema } from "effect"

const schema = Schema.Exit(
  Schema.FiniteFromString,
  Schema.Trim,
  Schema.Defect(),
)

Schema.decodeUnknownSync(schema)(Exit.succeed("1")) // => Exit.succeed(1)
Schema.decodeUnknownSync(schema)(Exit.fail(" error ")) // => Exit.fail("error")

Schema.encodeSync(schema)(Exit.succeed(1)) // => Exit.succeed("1")

其 JSON 表示形式在成功时使用 { _tag: "Success", value },在失败时使用 { _tag: "Failure", cause }

示例(Exit 的 JSON 形式)

import { Exit, Schema } from "effect"

const schema = Schema.toCodecJson(
  Schema.Exit(Schema.FiniteFromString, Schema.String, Schema.Defect()),
)

Schema.decodeUnknownSync(schema)({ _tag: "Success", value: "1" }) // => Exit.succeed(1)
Schema.encodeSync(schema)(Exit.fail("not found")) // => { _tag: "Failure", cause: [{ _tag: "Fail", error: "not found" }] }

Schema.Defect() 会把与 JSON 兼容的 defect 数据转换回 defect。带有 namemessage 以及可选 stack 的对象会被重建为 JavaScript 错误。

Collections

Effect 集合的 schema 要求两侧都是集合值,并在解码和编码期间应用元素 schema。它们的 JSON codec 使用值数组或键值对条目数组。

ReadonlySet

示例(ReadonlySet 的值与其 JSON 形式)

import { Schema } from "effect"

const RuntimeSet = Schema.ReadonlySet(Schema.FiniteFromString)

Schema.decodeUnknownSync(RuntimeSet)(new Set(["1", "2"])) // => new Set([1, 2])
Schema.encodeSync(RuntimeSet)(new Set([1, 2])) // => new Set(["1", "2"])

const JsonSet = Schema.toCodecJson(RuntimeSet)

Schema.decodeUnknownSync(JsonSet)(["1", "2"]) // => new Set([1, 2])
Schema.encodeSync(JsonSet)(new Set([1, 2])) // => ["1", "2"]

ReadonlyMap

示例(ReadonlyMap 的值与其 JSON 形式)

import { Schema } from "effect"

const RuntimeMap = Schema.ReadonlyMap(Schema.String, Schema.FiniteFromString)

Schema.decodeUnknownSync(RuntimeMap)(new Map([["a", "1"]])) // => new Map([["a", 1]])
Schema.encodeSync(RuntimeMap)(new Map([["a", 1]])) // => new Map([["a", "1"]])

const JsonMap = Schema.toCodecJson(RuntimeMap)

Schema.decodeUnknownSync(JsonMap)([["a", "1"]]) // => new Map([["a", 1]])
Schema.encodeSync(JsonMap)(new Map([["a", 1]])) // => [["a", "1"]]

HashSet

示例(HashSet 的值与其 JSON 形式)

import { HashSet, Schema } from "effect"

const RuntimeSet = Schema.HashSet(Schema.FiniteFromString)

Schema.decodeUnknownSync(RuntimeSet)(HashSet.fromIterable(["1", "2"])) // => HashSet.fromIterable([1, 2])

const JsonSet = Schema.toCodecJson(RuntimeSet)

Schema.decodeUnknownSync(JsonSet)(["1", "2"]) // => HashSet.fromIterable([1, 2])
Schema.encodeSync(JsonSet)(HashSet.fromIterable([1, 2])) // => ["1", "2"]

HashMap

示例(HashMap 的值与其 JSON 形式)

import { HashMap, Schema } from "effect"

const RuntimeMap = Schema.HashMap(Schema.String, Schema.FiniteFromString)

Schema.decodeUnknownSync(RuntimeMap)(HashMap.make(["a", "1"])) // => HashMap.make(["a", 1])

const JsonMap = Schema.toCodecJson(RuntimeMap)

Schema.decodeUnknownSync(JsonMap)([["a", "1"]]) // => HashMap.make(["a", 1])
Schema.encodeSync(JsonMap)(HashMap.make(["a", 1])) // => [["a", "1"]]

Duration

Schema.Duration 校验已有的 Duration 值。当编码值是字符串、毫秒数或纳秒 bigint 时,请使用转换 schema。

Schema编码类型类型
Schema.DurationDurationDuration
Schema.DurationFromStringstringDuration
Schema.DurationFromMillisnumberDuration
Schema.DurationFromNanosbigintDuration

示例(解码 Duration)

import { Duration, Schema } from "effect"

Schema.decodeUnknownSync(Schema.Duration)(Duration.seconds(2)) // => Duration.seconds(2)

Schema.decodeUnknownSync(Schema.DurationFromString)("2 seconds") // => Duration.seconds(2)
Schema.encodeSync(Schema.DurationFromString)(Duration.seconds(2)) // => "2000 millis"

Schema.decodeUnknownSync(Schema.DurationFromMillis)(2000) // => Duration.seconds(2)
Schema.encodeSync(Schema.DurationFromMillis)(Duration.seconds(2)) // => 2000

Schema.decodeUnknownSync(Schema.DurationFromNanos)(2_000_000_000n) // => Duration.nanos(2_000_000_000n)

Schema.Duration 的默认 JSON 表示形式是一个带标签对象,它保留毫秒、纳秒以及无限时长。

示例(Duration 的 JSON 形式)

import { Duration, Schema } from "effect"

const schema = Schema.toCodecJson(Schema.Duration)

Schema.encodeSync(schema)(Duration.seconds(2)) // => { _tag: "Millis", value: 2000 }
Schema.decodeUnknownSync(schema)({ _tag: "Millis", value: 2000 }) // => Duration.seconds(2)

Redacted

Schema.Redacted(value) 校验已有的 Redacted 值,并把 value 应用到其隐藏的内容上。若要解码原始值并将其包装为 Redacted,请使用 Schema.RedactedFromValue(value)

示例(把原始值解码为 Redacted)

import { Redacted, Schema } from "effect"

const schema = Schema.RedactedFromValue(Schema.Trim)

const secret = Schema.decodeUnknownSync(schema)(" secret ")

Redacted.value(secret) // => "secret"
Schema.encodeSync(schema)(secret) // => "secret"

Schema.Redacted(value) 的默认 JSON 表示形式会暴露编码后的内部值。如果某个 redacted 值绝不能被序列化,请设置 disallowJsonEncode: true

示例(阻止 JSON 编码)

import { Redacted, Schema } from "effect"

const Secret = Schema.Redacted(Schema.String, {
  label: "Secret",
  disallowJsonEncode: true,
})

const JsonSecret = Schema.toCodecJson(Secret)

// Encoding fails instead of exposing "password"
Schema.encodeSync(JsonSecret)(Redacted.make("password", { label: "Secret" }))