Skip to content

JavaScript / TypeScript SDK Reference

Installation

npm install anyvali

AnyVali requires Node.js 22 or later.

Imports

import {
  // Builder functions
  string, number, int, bool, null_, any, unknown, never,
  float32, float64,
  int8, int16, int32, int64,
  uint8, uint16, uint32, uint64,
  literal, enum_,
  array, tuple, object, record,
  union, intersection,
  optional, nullable,

  // Parse
  parse, safeParse,

  // Interchange
  exportSchema, importSchema,

  // Types
  type Infer,
  type InferInput,
  type ParseResult,
  type ValidationIssue,
  type AnyValiDocument,
  type ExportMode,
  type CoercionConfig,

  // Errors
  ValidationError,
  ISSUE_CODES,
} from "anyvali";

The forms layer is available from a separate entry point:

import { initForm, createFormBindings } from "anyvali/forms";

Quick Start

import { object, string, int, enum_, type Infer } from "anyvali";

// 1. Define a schema
const UserSchema = object({
  name: string().minLength(1).maxLength(100),
  email: string().format("email"),
  age: int().min(0).max(150),
  role: enum_(["admin", "user", "guest"]).default("user"),
});

// 2. Infer the TypeScript type
type User = Infer<typeof UserSchema>;
// => { name: string; email: string; age: number; role: "admin" | "user" | "guest" }

// 3. Parse input -- throws ValidationError on failure
const user = UserSchema.parse({
  name: "Alice",
  email: "alice@example.com",
  age: 30,
});
// => { name: "Alice", email: "alice@example.com", age: 30, role: "user" }

// 4. Safe parse -- returns a result object
const result = UserSchema.safeParse({ name: "", email: "bad" });
if (!result.success) {
  for (const issue of result.issues) {
    console.log(`${issue.path.join(".")}: [${issue.code}] ${issue.message}`);
  }
}

Type Inference

AnyVali provides full static type inference via the Infer<T> utility type. This is the flagship feature of the TypeScript SDK -- every parsed value carries the correct type without manual annotations or casts.

Basic Usage

import { string, int, bool, type Infer } from "anyvali";

const NameSchema = string();
type Name = Infer<typeof NameSchema>; // string

const AgeSchema = int();
type Age = Infer<typeof AgeSchema>; // number

const ActiveSchema = bool();
type Active = Infer<typeof ActiveSchema>; // boolean

Object Inference

Object schemas infer a full object type. Required fields become required properties; optional fields become optional properties with | undefined.

import { object, string, int, optional, type Infer } from "anyvali";

const UserSchema = object({
  name: string(),
  email: string().format("email"),
  age: optional(int().min(0)),
});

type User = Infer<typeof UserSchema>;
// => { name: string; email: string; age?: number | undefined }

const user = UserSchema.parse({ name: "Alice", email: "a@b.com" });
// user.name  -> string (no cast needed)
// user.age   -> number | undefined

Array and Tuple Inference

import { array, tuple, string, int, bool, type Infer } from "anyvali";

const TagsSchema = array(string());
type Tags = Infer<typeof TagsSchema>; // string[]

const CoordSchema = tuple([int(), int(), string()]);
type Coord = Infer<typeof CoordSchema>; // [number, number, string]

Union and Intersection Inference

import {
  union, intersection, object, string, int, literal,
  type Infer,
} from "anyvali";

// Union infers to a union type
const IdSchema = union([string(), int()]);
type Id = Infer<typeof IdSchema>; // string | number

// Intersection merges object shapes
const Named = object({ name: string() });
const Aged = object({ age: int() });
const Person = intersection([Named, Aged]);
type Person = Infer<typeof Person>; // { name: string } & { age: number }

Literal and Enum Inference

import { literal, enum_, type Infer } from "anyvali";

const StatusSchema = literal("active");
type Status = Infer<typeof StatusSchema>; // "active"

const RoleSchema = enum_(["admin", "user", "guest"] as const);
type Role = Infer<typeof RoleSchema>; // "admin" | "user" | "guest"

Pass as const to enum_() to infer narrow literal union types instead of string.

Nullable and Optional Inference

import { nullable, optional, string, type Infer } from "anyvali";

const NullableName = nullable(string());
type NullableName = Infer<typeof NullableName>; // string | null

const OptionalName = optional(string());
type OptionalName = Infer<typeof OptionalName>; // string | undefined

InferInput

InferInput<T> extracts the input type (what goes into parse()), which may differ from the output type when coercion or defaults are in play.

import { string, type Infer, type InferInput } from "anyvali";

const Schema = string().default("anonymous");
type Output = Infer<typeof Schema>;      // string
type Input = InferInput<typeof Schema>;   // string (the input is still expected to be a string)

Record Inference

import { record, int, type Infer } from "anyvali";

const ScoresSchema = record(int());
type Scores = Infer<typeof ScoresSchema>; // Record<string, number>

Schema Types

Primitives

string()

Creates a schema that validates string values. Supports chained constraint methods.

const s = string();
s.parse("hello"); // => "hello"
s.parse(42);      // throws: Expected string, received number

number()

Creates a schema for floating-point numbers. Defaults to float64 (IEEE 754 double precision).

const n = number();
n.parse(3.14); // => 3.14
n.parse("3");  // throws: Expected number, received string

int()

Creates a schema for integer values. Defaults to int64 (safe integer range). Rejects floats.

const i = int();
i.parse(42);   // => 42
i.parse(3.5);  // throws: Expected integer, received float

bool()

Creates a schema for boolean values.

const b = bool();
b.parse(true);  // => true
b.parse("yes"); // throws: Expected bool, received string

null_()

Creates a schema that only accepts null. Named null_ to avoid conflicting with the JavaScript keyword.

const n = null_();
n.parse(null); // => null
n.parse(0);    // throws: Expected null, received number

any()

Accepts any value without validation.

const a = any();
a.parse("hello"); // => "hello"
a.parse(42);      // => 42
a.parse(null);    // => null

unknown()

Accepts any value. Semantically identical to any() at runtime, but infers to unknown instead of any in TypeScript, forcing downstream code to narrow the type.

const u = unknown();
u.parse("hello"); // => "hello" (typed as unknown)

never()

Always fails validation. Useful for marking branches of a union that should be unreachable.

const n = never();
n.parse("anything"); // throws: Expected never

Numeric Widths

AnyVali provides width-specific numeric schemas that enforce range constraints automatically.

Float Types

float32()  // IEEE 754 single precision
float64()  // IEEE 754 double precision (same as number())

Signed Integer Types

int8()     // -128 to 127
int16()    // -32,768 to 32,767
int32()    // -2,147,483,648 to 2,147,483,647
int64()    // Number.MIN_SAFE_INTEGER to Number.MAX_SAFE_INTEGER

Unsigned Integer Types

uint8()    // 0 to 255
uint16()   // 0 to 65,535
uint32()   // 0 to 4,294,967,295
uint64()   // 0 to Number.MAX_SAFE_INTEGER

All integer types also reject non-integer values (floats).

const port = uint16();
port.parse(8080);   // => 8080
port.parse(-1);     // throws: Value -1 is below the minimum for uint16
port.parse(100000); // throws: Value 100000 is above the maximum for uint16
port.parse(3.5);    // throws: Expected integer, received float

All numeric width schemas inherit the same constraint methods as number() and int() (.min(), .max(), .exclusiveMin(), .exclusiveMax(), .multipleOf()).

Values

literal(value)

Creates a schema that matches exactly one specific value. Accepts string, number, boolean, or null.

const admin = literal("admin");
admin.parse("admin"); // => "admin"
admin.parse("user");  // throws: Expected literal admin, received user

const fortyTwo = literal(42);
fortyTwo.parse(42); // => 42

const yes = literal(true);
yes.parse(true); // => true

enum_(values)

Creates a schema that matches any value in the given array. Accepts strings and numbers.

const status = enum_(["active", "inactive", "pending"]);
status.parse("active");  // => "active"
status.parse("deleted"); // throws: Expected one of enum(active,inactive,pending)

// Use `as const` for narrow type inference
const role = enum_(["admin", "user"] as const);
type Role = Infer<typeof role>; // "admin" | "user"

Collections

array(itemSchema)

Creates a schema for arrays where every element must match the item schema.

const tags = array(string());
tags.parse(["a", "b", "c"]); // => ["a", "b", "c"]
tags.parse([1, 2, 3]);       // throws: Expected string, received number (at index 0)
tags.parse("not an array");  // throws: Expected array, received string

tuple(schemas)

Creates a schema for fixed-length arrays where each element matches the schema at its position.

const point = tuple([number(), number()]);
point.parse([1.5, 2.5]);     // => [1.5, 2.5]
point.parse([1]);             // throws: Tuple must have exactly 2 element(s)
point.parse([1, 2, 3]);      // throws: Tuple must have exactly 2 element(s)

const mixed = tuple([string(), int(), bool()]);
mixed.parse(["hello", 42, true]); // => ["hello", 42, true]

object(shape, options?)

Creates a schema for objects with named properties. By default, all properties are required and unknown keys are stripped.

const user = object({
  name: string(),
  age: int(),
});

user.parse({ name: "Alice", age: 30 });          // => { name: "Alice", age: 30 }
user.parse({ name: "Alice" });                    // throws: Required property "age" is missing
user.parse({ name: "Alice", age: 30, extra: 1 }); // => { name: "Alice", age: 30 }

Mark fields as optional using the optional() wrapper:

const user = object({
  name: string(),
  age: optional(int()),
});
user.parse({ name: "Alice" }); // => { name: "Alice" }

Control unknown key handling with the unknownKeys option:

// Strip unknown keys silently
const loose = object({ name: string() }, { unknownKeys: "strip" });
loose.parse({ name: "Alice", extra: 1 }); // => { name: "Alice" }

// Allow unknown keys in the output
const open = object({ name: string() }, { unknownKeys: "allow" });
open.parse({ name: "Alice", extra: 1 }); // => { name: "Alice", extra: 1 }

You can also change the mode after construction:

const schema = object({ name: string() }).unknownKeys("strip");

record(valueSchema)

Creates a schema for objects with arbitrary string keys where all values must match a single schema. Think of it as Record<string, T> in TypeScript.

const scores = record(int());
scores.parse({ alice: 100, bob: 95 }); // => { alice: 100, bob: 95 }
scores.parse({ alice: "high" });       // throws: Expected integer, received string

Composition

union(schemas)

Creates a schema that accepts any value matching at least one of the given schemas. Variants are tried in order; the first match wins.

const id = union([string(), int()]);
id.parse("abc"); // => "abc"
id.parse(42);    // => 42
id.parse(true);  // throws: Input did not match any variant of the union

intersection(schemas)

Creates a schema that requires the value to match all given schemas. For objects, the results are merged.

const withName = object({ name: string() }, { unknownKeys: "strip" });
const withAge = object({ age: int() }, { unknownKeys: "strip" });
const person = intersection([withName, withAge]);

person.parse({ name: "Alice", age: 30 }); // => { name: "Alice", age: 30 }
person.parse({ name: "Alice" });           // throws: Required property "age" is missing

Modifiers

optional(schema)

Wraps a schema so that undefined (absent) values are accepted. When the value is present, it must match the inner schema.

optional() is a standalone wrapper function, not a chainable method.

const maybeAge = optional(int());
maybeAge.parse(42);        // => 42
maybeAge.parse(undefined); // => undefined

// Typically used inside object()
const user = object({
  name: string(),
  bio: optional(string()),
});

nullable(schema)

Wraps a schema so that null values are accepted. When the value is non-null, it must match the inner schema.

nullable() is a standalone wrapper function, not a chainable method.

const nullableName = nullable(string());
nullableName.parse("Alice"); // => "Alice"
nullableName.parse(null);    // => null
nullableName.parse(42);      // throws: Expected string, received number

Constraints

String Constraints

All string constraint methods return a new schema instance (immutable builder pattern).

string().minLength(1)               // at least 1 character
string().maxLength(255)             // at most 255 characters
string().pattern("^[a-z]+$")       // must match regex pattern
string().startsWith("https://")    // must start with prefix
string().endsWith(".json")         // must end with suffix
string().includes("@")            // must contain substring
string().format("email")          // must match a named format

Chain multiple constraints:

const email = string()
  .minLength(5)
  .maxLength(254)
  .format("email");

String Formats

The following format names are supported:

Format Description
"email" Email address
"url" URL
"uuid" UUID (v1-v5)
"ipv4" IPv4 address
"ipv6" IPv6 address
"date" ISO 8601 date (YYYY-MM-DD)
"date-time" ISO 8601 date-time

Numeric Constraints

All numeric constraint methods apply to number(), int(), and all width-specific variants.

number().min(0)              // value >= 0
number().max(100)            // value <= 100
number().exclusiveMin(0)     // value > 0
number().exclusiveMax(100)   // value < 100
number().multipleOf(5)       // value must be divisible by 5

Chain multiple constraints:

const percentage = number()
  .min(0)
  .max(100)
  .multipleOf(0.01);

Array Constraints

array(string()).minItems(1)   // at least 1 element
array(string()).maxItems(10)  // at most 10 elements

// Combined
const tags = array(string()).minItems(1).maxItems(5);

Object Options

The unknownKeys option controls how keys not declared in the shape are handled:

Mode Behavior
"strip" (default) Silently removes extra keys from the output
"reject" Produces an unknown_key issue for each extra key
"allow" Passes extra keys through to the output
const stripped = object({ name: string() }); // unknownKeys defaults to "strip"
const strict = object({ name: string() }, { unknownKeys: "reject" });
const passthrough = object({ name: string() }, { unknownKeys: "allow" });

Coercion

Coercion transforms the input value before validation. It runs in step 2 of the parse pipeline, only when the value is present.

Usage

Call .coerce(config) on any schema to enable coercion:

const age = int().coerce({ from: "string" });
age.parse("42"); // => 42 (string coerced to integer)
age.parse(42);   // => 42 (already an integer, no coercion needed)

CoercionConfig

The CoercionConfig object supports the following properties:

Property Type Description
from string Source type for type conversion. Currently "string" is supported.
trim boolean Trim whitespace from string values
lower boolean Convert string to lowercase
upper boolean Convert string to uppercase

Available Coercions

String to Number

const n = number().coerce({ from: "string" });
n.parse("3.14"); // => 3.14
n.parse("");     // throws: coercion_failed

String to Integer

const i = int().coerce({ from: "string" });
i.parse("42");   // => 42
i.parse("3.5");  // throws: coercion_failed (not an integer string)

String to Boolean

const b = bool().coerce({ from: "string" });
b.parse("true");  // => true
b.parse("false"); // => false
b.parse("1");     // => true
b.parse("0");     // => false
b.parse("yes");   // throws: coercion_failed

String Transformations

const trimmed = string().coerce({ trim: true });
trimmed.parse("  hello  "); // => "hello"

const lower = string().coerce({ lower: true });
lower.parse("HELLO"); // => "hello"

const upper = string().coerce({ upper: true });
upper.parse("hello"); // => "HELLO"

Transformations can be combined:

const normalized = string().coerce({ trim: true, lower: true });
normalized.parse("  Hello World  "); // => "hello world"

Defaults

Defaults fill in missing (absent) values. They run in step 3 of the parse pipeline, after coercion and before validation.

Usage

Call .default(value) on any schema:

const role = string().default("user");
role.parse(undefined); // => "user"
role.parse("admin");   // => "admin"

const tags = array(string()).default([]);
tags.parse(undefined); // => []
tags.parse(["a"]);     // => ["a"]

Defaults work with optional fields in objects:

const config = object({
  theme: optional(string().default("light")),
  language: optional(string().default("en")),
});

config.parse({}); // => { theme: "light", language: "en" }
config.parse({ theme: "dark" }); // => { theme: "dark", language: "en" }

If the default value itself fails validation, a default_invalid issue is produced.

Export and Import

AnyVali schemas can be exported to a portable JSON document and imported back in any supported SDK.

exportSchema(schema, mode?)

Exports a schema to an AnyValiDocument object.

import { object, string, int, exportSchema } from "anyvali";

const schema = object({
  name: string().minLength(1),
  age: int().min(0),
});

// Portable mode (default) -- fails if schema uses non-portable features
const doc = exportSchema(schema);
// Or: const doc = exportSchema(schema, "portable");

// Extended mode -- includes language-specific extension namespaces
const extended = exportSchema(schema, "extended");

console.log(JSON.stringify(doc, null, 2));

You can also call .export(mode?) directly on a schema instance:

const doc = schema.export("portable");

The document structure:

{
  "anyvaliVersion": "1.0",
  "schemaVersion": "1",
  "root": { ... },
  "definitions": {},
  "extensions": {}
}

importSchema(doc)

Imports an AnyValiDocument into a live schema that can be used for parsing.

import { importSchema } from "anyvali";

const doc = {
  anyvaliVersion: "1.0",
  schemaVersion: "1",
  root: {
    kind: "object",
    properties: {
      name: { kind: "string", minLength: 1 },
      age: { kind: "int", min: 0 },
    },
    required: ["name", "age"],
    unknownKeys: "strip",
  },
  definitions: {},
  extensions: {},
};

const schema = importSchema(doc);
const user = schema.parse({ name: "Alice", age: 30 });

Export Modes

Mode Behavior
"portable" Only emits portable schema features. Fails if the schema depends on non-portable constructs.
"extended" Emits the core schema plus language-specific extensions in the extensions field.

Error Handling

ValidationError

When parse() fails, it throws a ValidationError containing a list of issues:

import { string, ValidationError } from "anyvali";

try {
  string().minLength(5).parse("hi");
} catch (err) {
  if (err instanceof ValidationError) {
    console.log(err.message);
    // "[too_small] String must have at least 5 character(s)"

    for (const issue of err.issues) {
      console.log(issue.code);    // "too_small"
      console.log(issue.message); // "String must have at least 5 character(s)"
      console.log(issue.path);    // []
    }
  }
}

ParseResult

safeParse() never throws. It returns a discriminated union:

type ParseResult<T> =
  | { success: true; data: T }
  | { success: false; issues: ValidationIssue[] };
const result = string().safeParse(42);

if (result.success) {
  console.log(result.data); // string
} else {
  for (const issue of result.issues) {
    console.log(issue);
  }
}

ValidationIssue

Each issue has the following structure:

interface ValidationIssue {
  code: string;                   // Machine-readable issue code
  message: string;                // Human-readable description
  path: (string | number)[];     // Path to the failing value
  expected?: string;              // What was expected
  received?: string;              // What was received
  meta?: Record<string, unknown>; // Additional metadata
}

The path array describes the location of the error within nested structures:

const schema = object({
  users: array(object({
    email: string().format("email"),
  })),
});

const result = schema.safeParse({
  users: [{ email: "not-an-email" }],
});

// result.issues[0].path => ["users", 0, "email"]

Issue Codes

All issue codes are available as constants via ISSUE_CODES:

import { ISSUE_CODES } from "anyvali";
Code When
invalid_type Value is the wrong type
required Required property is missing
unknown_key Object has an undeclared key (when unknownKeys is "reject")
too_small String too short, number too low, or array too few items
too_large String too long, number too high, or array too many items
invalid_string String fails a pattern, startsWith, endsWith, includes, or format check
invalid_number Number fails a multipleOf check
invalid_literal Value does not match the expected literal
invalid_union Value does not match any variant in a union
coercion_failed Coercion could not convert the input
default_invalid The materialized default value failed validation
custom_validation_not_portable Non-portable custom validation was encountered
unsupported_extension Unknown extension namespace in an imported document
unsupported_schema_kind Unknown schema kind in an imported document

Common Patterns

Validating Environment Variables

Use unknownKeys: "strip" when parsing objects that contain many extra keys you don't care about, like process.env:

import { object, string, int, optional, type Infer } from "anyvali";

const EnvSchema = object({
  NODE_ENV: optional(string()).default("development"),
  PORT: optional(int().coerce({ from: "string" })).default(3000),
  DATABASE_URL: string(),
}, { unknownKeys: "strip" });

type Env = Infer<typeof EnvSchema>;
// => { NODE_ENV?: string | undefined; PORT?: number | undefined; DATABASE_URL: string }

const env = EnvSchema.parse(process.env);
// Returns only { NODE_ENV, PORT, DATABASE_URL } -- all other env vars are stripped

"strip" is the default, so this option is only needed when you want to be explicit.

Mode What happens with extra keys
"strip" (default) Extra keys silently removed from output
"reject" Parse fails with unknown_key issues
"allow" Extra keys passed through to output

Eagerly Evaluated vs Lazy Defaults

.default() accepts any value of the correct type. Expressions like process.cwd() are evaluated immediately when the schema is created and stored as a static value -- this works fine:

const ConfigSchema = object({
  profile: optional(string()).default("default"),
  appDir: optional(string()).default(process.cwd()), // evaluated once, stored as e.g. "/home/user/app"
}, { unknownKeys: "strip" });

What AnyVali does not support is lazy function defaults that re-evaluate on each parse call (like Zod's .default(() => crypto.randomUUID())). AnyVali defaults are always a single stored value, not a callback. If you need a fresh value on every parse, apply it after:

const config = ConfigSchema.parse(input);
config.requestId ??= crypto.randomUUID(); // different on each call

Eagerly evaluated defaults export portably -- the stored string travels in the JSON document. Lazy defaults cannot be serialized.

Forms

The anyvali/forms entry point provides a browser-side forms integration layer that connects AnyVali schemas to HTML forms, including native constraint validation and htmx support.

createFormBindings(options)

Generates HTML attribute objects for form fields and error slots based on a schema.

import { createFormBindings } from "anyvali/forms";
import { object, string, int } from "anyvali";

const schema = object({
  name: string().minLength(1).maxLength(100),
  age: int().min(0).max(150),
});

const form = createFormBindings({ schema });

// Get attributes for a field (name, type, required, min, max, etc.)
const nameAttrs = form.field("name");
// => { name: "name", required: true, minLength: 1, maxLength: 100, ... }

const ageAttrs = form.field("age");
// => { name: "age", required: true, type: "number", min: 0, max: 150, step: 1, ... }

// Get attributes for an error display slot
const nameError = form.errorSlot("name");
// => { id: "anyvali-error-name", "data-anyvali-error-for": "name", "aria-live": "polite" }

initForm(target, options)

Attaches live validation to a <form> element. Returns a FormController.

import { initForm } from "anyvali/forms";

const controller = initForm("#my-form", {
  schema: UserSchema,
  validateOn: ["blur", "submit"],  // when to validate (default: ["blur", "submit"])
  nativeValidation: true,          // apply native HTML constraints (default: true)
  reportValidity: true,            // call reportValidity() on fields (default: true)
  htmx: true,                     // integrate with htmx (default: true)
});

controller.validate();   // manually trigger validation, returns boolean
controller.getValues();  // read current form values as an object
controller.getResult();  // run safeParse and return ParseResult
controller.destroy();    // remove all event listeners

API Reference

Builder Functions

Function Returns Description
string() StringSchema String values
number() NumberSchema Float64 numbers
float32() Float32Schema Float32 numbers
float64() Float64Schema Float64 numbers
int() IntSchema Int64 integers
int8() Int8Schema Int8 integers
int16() Int16Schema Int16 integers
int32() Int32Schema Int32 integers
int64() Int64Schema Int64 integers
uint8() Uint8Schema Uint8 integers
uint16() Uint16Schema Uint16 integers
uint32() Uint32Schema Uint32 integers
uint64() Uint64Schema Uint64 integers
bool() BoolSchema Boolean values
null_() NullSchema Null only
any() AnySchema Any value (typed as any)
unknown() UnknownSchema Any value (typed as unknown)
never() NeverSchema Always fails
literal(value) LiteralSchema<T> Exact value match
enum_(values) EnumSchema<T> One of the listed values
array(items) ArraySchema<T> Array of uniform type
tuple(schemas) TupleSchema<T> Fixed-length typed array
object(shape, options?) ObjectSchema<T> Object with named properties
record(valueSchema) RecordSchema<T> Object with uniform value type
union(variants) UnionSchema<T> First-match union
intersection(schemas) IntersectionSchema<T> All-match intersection
optional(schema) OptionalSchema<T> Allows undefined
nullable(schema) NullableSchema<T> Allows null

BaseSchema Methods

Available on all schema instances:

Method Returns Description
.parse(input) T Parse or throw ValidationError
.safeParse(input) ParseResult<T> Parse and return result object
.default(value) this Set a default for absent values
.coerce(config) this Configure coercion behavior
.export(mode?) AnyValiDocument Export to interchange document

StringSchema Methods

Method Parameter Description
.minLength(n) number Minimum string length
.maxLength(n) number Maximum string length
.pattern(p) string Regex pattern to match
.startsWith(s) string Required prefix
.endsWith(s) string Required suffix
.includes(s) string Required substring
.format(f) StringFormat Named format validation

NumberSchema / IntSchema Methods

Method Parameter Description
.min(n) number Minimum value (inclusive)
.max(n) number Maximum value (inclusive)
.exclusiveMin(n) number Minimum value (exclusive)
.exclusiveMax(n) number Maximum value (exclusive)
.multipleOf(n) number Value must be divisible by n

ArraySchema Methods

Method Parameter Description
.minItems(n) number Minimum number of elements
.maxItems(n) number Maximum number of elements

ObjectSchema Methods

Method Parameter Description
.unknownKeys(mode) UnknownKeyMode Set unknown key handling ("reject", "strip", "allow")

Top-Level Functions

Function Signature Description
parse parse<T>(schema, input): T Parse using a schema reference
safeParse safeParse<T>(schema, input): ParseResult<T> Safe parse using a schema reference
exportSchema exportSchema(schema, mode?): AnyValiDocument Export a schema to interchange format
importSchema importSchema(doc): BaseSchema Import a schema from interchange format

Types

Type Description
Infer<T> Extract the output type from a schema
InferInput<T> Extract the input type from a schema
ParseResult<T> { success: true; data: T } \| { success: false; issues: ValidationIssue[] }
ValidationIssue { code, message, path, expected?, received?, meta? }
ValidationError Error class with .issues: ValidationIssue[]
AnyValiDocument { anyvaliVersion, schemaVersion, root, definitions, extensions }
ExportMode "portable" \| "extended"
UnknownKeyMode "reject" \| "strip" \| "allow"
CoercionConfig { from?, trim?, lower?, upper? }
StringFormat "email" \| "url" \| "uuid" \| "ipv4" \| "ipv6" \| "date" \| "date-time"
SchemaKind Union of all schema kind strings
IssueCode Union of all issue code strings