Validit
⚡ Quick Reference
Package: @vielzeug/validit · Category: Validation
Key exports: v, toJsonSchema, ValidationError, configure
When to use: Zero-dep schema validation with strict-by-default objects, async refinements, coercion, JSON Schema output, and full TypeScript inference.
@vielzeug/validit is a zero-dependency schema validation library for TypeScript projects. It gives you a fluent schema API, runtime validation, and precise input/output typing with InferInput<T> and Infer<T>.
Installation
pnpm add @vielzeug/validitnpm install @vielzeug/validityarn add @vielzeug/validitQuick Start
import { v, type Infer } from '@vielzeug/validit';
const UserSchema = v.object({
id: v.coerce.number().int().positive(),
name: v.string().trim().min(1),
email: v.string().trim().email(),
role: v.union('admin', 'editor', 'viewer').default('viewer'),
tags: v.array(v.string()).unique().default([]),
});
type User = Infer<typeof UserSchema>;
const result = UserSchema.safeParse({
id: '42',
name: 'Ada',
email: 'ada@example.com',
});
if (result.success) {
const user: User = result.data;
console.log(user.id); // 42
} else {
const { fieldErrors, formErrors } = result.error.flattenFirst();
console.log(fieldErrors, formErrors);
}Why Validit?
Ad-hoc validation tends to spread across handlers and services, making rules hard to reuse and error responses inconsistent.
// Before - manual checks
function parseUser(input: unknown) {
if (typeof input !== 'object' || input === null) throw new Error('Invalid payload');
const data = input as Record<string, unknown>;
if (typeof data.email !== 'string' || !data.email.includes('@')) throw new Error('Invalid email');
if (typeof data.age !== 'number' || data.age < 18) throw new Error('Invalid age');
return { email: data.email, age: data.age };
}
// After - Validit
const UserSchema = v.object({
email: v.string().email(),
age: v.number().int().min(18),
});
const result = UserSchema.safeParse(payload);
if (!result.success) {
const { fieldErrors, formErrors } = result.error.flatten();
}| Feature | Validit | Zod | Yup |
|---|---|---|---|
| Bundle size | 8.8 KB | ~62 kB | ~14 kB |
| Type inference | ✅ Infer<T> | ✅ | Partial |
| Coercion API | ✅ v.coerce.* | ✅ | ✅ |
| Async validation | ✅ .check() | ✅ | ✅ |
| Error flattening | ✅ flatten() + flattenFirst() | ✅ | Partial |
| Zero dependencies | ✅ | ✅ | ❌ |
Use Validit when you want a fluent schema API with strong TypeScript inference, structured errors, and zero dependencies.
Consider alternatives when you are already standardized on another validator ecosystem and migration cost outweighs the API benefits.
Features
- Schema factories: primitives, collections, literals, unions, intersections, lazy schemas, discriminated variants, and enum helpers
- Input/output inference:
InferInput<T>for accepted inputs plusInfer<T>for parsed outputs - Sync and async validation:
.check()withparse*andsafeParse* - Advanced validation hooks:
ctx.addIssue()for multi-issue/path-aware validation - Preprocess and coerce:
schema.preprocess(...)plusv.coerce.string(),number(),boolean(), anddate() - Expanded schema coverage:
v.bigint(),v.set(), andv.map() - Error ergonomics:
ValidationError,Issue,ErrorCode,error.flatten(), anderror.flattenFirst() - Object and tuple composition: object
.strip()/.relaxed()modes and tuple.rest() - String and number format constraints: validators like
.ulid(),.jwt(),.duration(), and.finite() - Strict by default objects: unknown keys are rejected unless
.relaxed()is used - Nested global message customization:
configure({ messages })andreset() - Flexible roots:
v.any()andv.unknown()when you want to start from an unconstrained schema - Zero dependencies: no runtime dependencies, no adapter layer required
Compatibility
| Environment | Support |
|---|---|
| Browser | ✅ |
| Node.js | ✅ |
| SSR | ✅ |
| Deno | ✅ |