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

从 Schema 到 Standard Schema

生成 Standard Schema V1。

Schema.toStandardSchemaV1 通过 Standard Schema V1 接口暴露一个 Effect schema。得到的对象可以传给支持该标准的库,同时保留原有的 Effect schema API。

示例(生成 Standard Schema V1)

import { Schema } from "effect"

const schema = Schema.Struct({
  name: Schema.String,
})

// Convert an Effect schema into a Standard Schema V1 object
const standardSchema = Schema.toStandardSchemaV1(schema)

standardSchema["~standard"].vendor // => "effect"
Schema Restrictions

该 schema 不能要求 decoding services:其 DecodingServices 必须是 never

同步校验与异步校验

Standard Schema 的 validate 方法会首先尝试同步解码。如果解码过程中遇到异步的 transformation 或 check,则改为返回一个 Promise

示例(处理同步与异步校验)

import { Effect, Schema, SchemaGetter } from "effect"

// Utility function to display sync and async results
const print = <T>(t: T) =>
  t instanceof Promise
    ? t.then((x) => console.log("Promise", JSON.stringify(x, null, 2)))
    : console.log("Value", JSON.stringify(t, null, 2))

// Define a synchronous schema
const sync = Schema.Struct({
  name: Schema.String,
})

// Generate a Standard Schema V1 object
const syncStandardSchema = Schema.toStandardSchemaV1(sync)

// Validate synchronously
print(syncStandardSchema["~standard"].validate({ name: null }))
syncStandardSchema["~standard"].validate({ name: null }) // => { issues: [{ path: ["name"], message: "Expected string" }] }
/*
Output:
{
  "issues": [
    {
      "path": [
        "name"
      ],
      "message": "Expected string"
    }
  ]
}
*/

// Define an asynchronous schema with a transformation
const async = sync.pipe(
  Schema.decodeTo(
    Schema.Struct({
      name: Schema.NonEmptyString,
    }),
    {
      // Simulate an asynchronous validation delay
      decode: SchemaGetter.transformOrFail((x) =>
        Effect.sleep("100 millis").pipe(Effect.as(x)),
      ),
      encode: SchemaGetter.passthrough(),
    },
  ),
)

// Generate a Standard Schema V1 object
const asyncStandardSchema = Schema.toStandardSchemaV1(async)

// Validate asynchronously
print(asyncStandardSchema["~standard"].validate({ name: "" }))
await asyncStandardSchema["~standard"].validate({ name: "" }) // => { issues: [{ path: ["name"], message: "Expected a value with a length of at least 1" }] }
/*
Output:
Promise {
  "issues": [
    {
      "path": [
        "name"
      ],
      "message": "Expected a value with a length of at least 1"
    }
  ]
}
*/

Defect

如果校验期间出现意外的 defect,它会被报告为单个不带 path 的 issue。这样可以确保意外的错误不会中断 schema 校验,同时仍会被捕获并报告。

示例(处理 Defect)

import { Effect, Schema, SchemaGetter } from "effect"

// Define a schema with a defect in the decode function
const defect = Schema.String.pipe(
  Schema.decodeTo(Schema.String, {
    // Simulate an internal failure
    decode: SchemaGetter.transformOrFail(() => Effect.die("Boom!")),
    encode: SchemaGetter.passthrough(),
  }),
)

// Generate a Standard Schema V1 object
const defectStandardSchema = Schema.toStandardSchemaV1(defect)

// Validate input, triggering a defect
console.log(defectStandardSchema["~standard"].validate("a"))
/*
Output:
{ issues: [ { message: 'Error: Boom!' } ] }
*/

Standard Schema 的失败会使用 Error Formatters 中所述的同一个 formatter。向 Schema.toStandardSchemaV1 传入 leafHookcheckHookparseOptions,即可自定义其输出。