@loydjs/schema
v1.1.0
Published
Loyd schema — functional, tree-shakeable DSL
Maintainers
Readme
Overview
@loydjs/schema provides every schema type you need - primitives, composites, modifiers, and refinements. Every export is tree-shakeable: if you only use string() and number(), only those end up in your bundle.
Installation
npm install @loydjs/schema @loydjs/coreRequires
@loydjs/core· Node.js ≥ 20 · TypeScript ≥ 5.4 ·"strict": trueintsconfig.json
Primitives
string()
import { string } from "@loydjs/schema";
string()
.minLength(2)
.maxLength(100)
.email()
.url()
.uuid()
.regex(/^\d{4}$/)
.startsWith("prefix_")
.endsWith("_suffix")
.includes("keyword")
.nonempty()
.trim()
.toLowerCase()
.toUpperCase()number()
import { number } from "@loydjs/schema";
number()
.min(0) // >= 0
.max(120) // <= 120
.gt(0) // > 0
.gte(1) // >= 1
.lt(100) // < 100
.lte(99) // <= 99
.int() // integer only
.positive() // > 0
.negative() // < 0
.nonnegative() // >= 0
.multipleOf(5)
.finite()
.safe() // Number.isSafeIntegerboolean()
import { boolean } from "@loydjs/schema";
const Active = boolean();bigint()
import { bigint } from "@loydjs/schema";
const Id = bigint();date()
import { date } from "@loydjs/schema";
const CreatedAt = date();literal(value)
import { literal } from "@loydjs/schema";
const Admin = literal("admin");
const Active = literal(true);
const Zero = literal(0);Composites
object(shape)
import { object, string, number } from "@loydjs/schema";
const User = object({
name: string().minLength(2),
email: string().email(),
age: number().int().min(0),
});
// Unknown key handling
User.strict(); // error on unknown keys
User.strip(); // remove unknown keys (default)
User.passthrough(); // keep unknown keys
// Shape operations
User.pick(["name", "email"]);
User.omit(["age"]);
User.partial(); // all fields optional
User.required(); // all fields required
User.extend({ role: string() });
User.merge(OtherSchema);array(element)
import { array, string } from "@loydjs/schema";
array(string())
.min(1)
.max(100)
.length(5)
.nonempty()tuple(elements)
import { tuple, string, number } from "@loydjs/schema";
const Point = tuple([number(), number()]);
// [number, number]union(options)
import { union, string, number } from "@loydjs/schema";
const StringOrNumber = union([string(), number()]);discriminatedUnion(key, options)
import { discriminatedUnion, object, literal, string, number } from "@loydjs/schema";
// O(1) variant lookup via Map - compiled to constant-time dispatch
const Shape = discriminatedUnion("kind", [
object({ kind: literal("circle"), radius: number().min(0) }),
object({ kind: literal("rect"), width: number().min(0), height: number().min(0) }),
object({ kind: literal("triangle"), base: number().min(0), height: number().min(0) }),
]);record(valueSchema)
import { record, number } from "@loydjs/schema";
const Scores = record(number().int().min(0).max(100));
// Record<string, number>map(keySchema, valueSchema)
import { map, string, number } from "@loydjs/schema";
const Cache = map(string(), number());set(elementSchema)
import { set, string } from "@loydjs/schema";
const Tags = set(string());Modifiers
optional(schema)
import { optional, string } from "@loydjs/schema";
const MaybeEmail = optional(string().email());
// string | undefinednullable(schema)
import { nullable, string } from "@loydjs/schema";
const MaybeName = nullable(string());
// string | nullnullish(schema)
import { nullish, string } from "@loydjs/schema";
const MaybeValue = nullish(string());
// string | null | undefinedbrand(schema, brand)
import { brand, string } from "@loydjs/schema";
const UserId = brand(string().uuid(), "UserId");
type UserId = Infer<typeof UserId>; // string & { readonly [brand]: "UserId" }transform(schema, fn)
import { transform, string } from "@loydjs/schema";
const TrimmedEmail = transform(
string().email(),
(email) => email.toLowerCase().trim()
);pipe(schema, ...rules)
import { pipe, string, minLength, email } from "@loydjs/schema";
// Compose rules functionally
const EmailField = pipe(string(), minLength(1), email());Refinements
refine(schema, predicate, options)
import { refine, string } from "@loydjs/schema";
const StrongPassword = refine(
string().minLength(8),
(v) => /[A-Z]/.test(v) && /[0-9]/.test(v),
{ code: "ERR_PASSWORD_TOO_WEAK" }
);refineAsync(schema, predicate, options)
import { refineAsync, string } from "@loydjs/schema";
const UniqueUsername = refineAsync(
string().minLength(3),
async (username) => {
const taken = await db.users.exists({ username });
return !taken;
},
{ code: "ERR_USERNAME_TAKEN" }
);defineRule(definition, predicate)
Define a reusable rule with a name and code that can be applied to any schema.
import { defineRule, string } from "@loydjs/schema";
const noEmoji = defineRule(
{ code: "ERR_STRING_HAS_EMOJI", description: "No emoji allowed" },
(v: string) => !/\p{Emoji}/u.test(v)
);
const CleanString = noEmoji.apply(string());Dependencies
| Package | Role |
|:---|:---|
| @loydjs/core | BaseSchema, LoydResult |
| @loydjs/types | SchemaMap, InferSchemaMap |
Documentation
License
MIT © b3nito404
