Warning: Effeck is v0. The language will change in major, breaking ways. It is not suitable for production use.

Schema to Standard Schema

Standard Schema adaptation works as in Effect. It exposes a codec to libraries that implement the Standard Schema V1 validation interface while retaining the original Schema methods. The codec must have no decoding service requirements. Plain builders follow the trusted call rules.

Adapting codecs to the standard validation interface

const Dispatch = Schema.Struct({
  reference: Schema.NonEmptyString,
  count: Schema.FiniteFromString
})
const DispatchStandard = Schema.toStandardSchemaV1(Dispatch, {
  parseOptions: { errors: "all" }
})

function standardMetadata() {
  return DispatchStandard["~standard"].vendor // "effect"
}

toStandardSchemaV1 adds the "~standard" interface. Validation returns { value } on success or { issues } on failure, and performs decoding, including transformations. Pass the adapted schema to a compatible library from that library's normal TypeScript integration module. It still exposes the original Effect Schema APIs.

Choosing synchronous or asynchronous validation

const ReviewedDispatch = Dispatch.pipe(Schema.decode({
  decode: SchemaGetter.checkEffect((_dispatch) => {
    sleep("5 millis")
    return true
  }),
  encode: SchemaGetter.passthrough()
}))
const ReviewedStandard = Schema.toStandardSchemaV1(ReviewedDispatch)

function validateDispatch(input: unknown) {
  return try((standard, input) => Promise.resolve(standard["~standard"].validate(input)), (cause) => new ValidationBoundaryError({ cause }), ReviewedStandard, input)
}

error ValidationBoundaryError {
  cause: unknown
}

The standard interface attempts synchronous validation first. If it encounters asynchronous work, it returns a Promise instead of a direct result. Promise.resolve inside an explicit foreign-code boundary normalizes both cases without await in Effeck. Prefer Schema.decodeUnknownEffect for ordinary Effeck application code; the standard interface is most useful for interoperability.

Inside the try hatch, plain TypeScript calls are allowed. Promise.resolve produces a Promise for either validation result shape, so no special mixed-return call rule is needed. The boundary maps synchronous exceptions and Promise rejections to ValidationBoundaryError; reported validation issues remain data.

Handling defects during validation

const BrokenLabel = Schema.String.pipe(Schema.decode({
  decode: SchemaGetter.transformEffect((_label) => die("label invariant failed")),
  encode: SchemaGetter.passthrough()
}))
const BrokenStandard = Schema.toStandardSchemaV1(BrokenLabel)

function inspectBrokenValidation() {
  return try((standard) => standard["~standard"].validate("crate"), BrokenStandard)
}

The adapter reports an unexpected defect as one issue without a path, rather than exposing it as a normal field-validation failure. This is the adapter's behavior; ordinary Effeck catch still does not catch defects. Keep internal diagnostics at an application boundary if a defect needs investigation instead of relying only on the validation message.

Pass leafHook, checkHook, and parseOptions to customize the adapter. Its structured failures use the same issue formatter described in Error Formatters.

Upstream page