Skip to content

Schema interop

import * as Schema from '@stopcock/fp/schema'

The schema module implements the Standard Schema V1 interface. It lets @stopcock/fp produce and consume validators shared with schema libraries, forms, RPC frameworks, and other Standard Schema-aware tools without growing a competing schema language.

const positive = Schema.fromPredicate(
(value: unknown): value is number =>
typeof value === 'number' && value > 0,
() => Schema.issue('Expected a positive number'),
)

For decoders and transformations, use make:

import { err, ok } from '@stopcock/fp'
const integerFromString = Schema.make((value) => {
if (typeof value !== 'string') return err('Expected a string')
const parsed = Number(value)
return Number.isInteger(parsed)
? ok(parsed)
: err(Schema.issue('Expected an integer'))
})

A decoder may return a Result or a promise of a Result. String errors, individual issues, and issue arrays are normalized to Standard Schema issues.

const result = Schema.validateSync(schema)(input)
// Result<Output, readonly Issue[]>
const asyncResult = await Schema.validate(schema)(input)
// Promise<Result<Output, readonly Issue[]>>

validateSync throws a TypeError if the validator is asynchronous. validate accepts either kind.

Schema.isStandardSchema(value)
Schema.issues(error)
Schema.issue(message, path)
const labelled = Schema.map(positive, (value) => `positive:${value}`)
const maybePositive = Schema.optional(positive)
const nullablePositive = Schema.nullable(positive)

These combinators preserve a synchronous underlying validator. Wrapping a sync schema never introduces a promise.