← Volver al listado de tecnologías
Introducción a Valibot: Validación de Esquemas Moderna y Ligera
Introducción a Valibot: Validación de Esquemas Moderna y Ligera
¿Qué es Valibot?
Valibot es una biblioteca de validación de esquemas para TypeScript que se destaca por su diseño modular y su tamaño extremadamente pequeño. Creada por Fabian Hiller, Valibot ofrece una alternativa ligera a bibliotecas como Zod, con un enfoque en el rendimiento y la optimización del bundle size.
Características Principales
1. Ultra Ligero
- Bundle size mínimo (< 1KB para validaciones básicas)
- Tree-shakeable: solo incluyes lo que usas
- Ideal para aplicaciones donde el tamaño importa
2. Type-Safe
- Inferencia de tipos TypeScript completa
- Autocompletado inteligente
- Errores de compilación descriptivos
3. Modular
- Arquitectura basada en funciones
- Composición flexible de validadores
- Extensible con validadores personalizados
4. Rendimiento
- Validación rápida y eficiente
- Sin dependencias externas
- Optimizado para producción
Instalación
# npm
npm install valibot
# yarn
yarn add valibot
# pnpm
pnpm add valibot
# bun
bun add valibot
Primeros Pasos
1. Esquema Básico
import { object, string, number, email, minLength, minValue, parse } from 'valibot';
// Definir un esquema de usuario
const UserSchema = object({
name: string([minLength(2, 'El nombre debe tener al menos 2 caracteres')]),
email: string([email('Email inválido')]),
age: number([minValue(18, 'Debe ser mayor de 18 años')])
});
// Usar el esquema
try {
const validUser = parse(UserSchema, {
name: 'Juan',
email: '[email protected]',
age: 25
});
console.log('Usuario válido:', validUser);
} catch (error) {
console.error('Error de validación:', error);
}
2. Tipos Primitivos
import { string, number, boolean, date, parse } from 'valibot';
// String
const nameSchema = string();
const name = parse(nameSchema, 'Juan');
// Number
const ageSchema = number();
const age = parse(ageSchema, 25);
// Boolean
const activeSchema = boolean();
const isActive = parse(activeSchema, true);
// Date
const birthDateSchema = date();
const birthDate = parse(birthDateSchema, new Date());
3. Arrays y Objetos
import { array, object, string, number } from 'valibot';
// Array de strings
const tagsSchema = array(string());
// Objeto anidado
const ProductSchema = object({
id: number(),
name: string(),
tags: array(string()),
details: object({
description: string(),
price: number()
})
});
Validaciones Comunes
1. Strings
import { string, minLength, maxLength, length, regex, email, url } from 'valibot';
// Longitud mínima y máxima
const passwordSchema = string([
minLength(8, 'Mínimo 8 caracteres'),
maxLength(20, 'Máximo 20 caracteres')
]);
// Longitud exacta
const codeSchema = string([length(6, 'El código debe tener 6 caracteres')]);
// Expresión regular
const phoneSchema = string([
regex(/^\+?[1-9]\d{1,14}$/, 'Número de teléfono inválido')
]);
// Email
const emailSchema = string([email('Email inválido')]);
// URL
const websiteSchema = string([url('URL inválida')]);
2. Números
import { number, minValue, maxValue, integer } from 'valibot';
// Rango de valores
const ageSchema = number([
minValue(0, 'La edad no puede ser negativa'),
maxValue(150, 'La edad no puede ser mayor a 150')
]);
// Números enteros
const quantitySchema = number([
integer('Debe ser un número entero'),
minValue(1, 'La cantidad mínima es 1')
]);
3. Opcionales y Valores por Defecto
import { object, string, optional, nullable, transform } from 'valibot';
const UserSchema = object({
// Campo opcional
nickname: optional(string()),
// Campo nullable
middleName: nullable(string()),
// Valor por defecto
role: transform(
optional(string()),
(value) => value || 'user'
)
});
Validación de Formularios
Ejemplo con React
import { object, string, email, minLength, safeParse } from 'valibot';
import { useState } from 'react';
const LoginSchema = object({
email: string([email('Email inválido')]),
password: string([minLength(8, 'Mínimo 8 caracteres')])
});
function LoginForm() {
const [errors, setErrors] = useState<Record<string, string>>({});
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data = Object.fromEntries(formData);
const result = safeParse(LoginSchema, data);
if (result.success) {
console.log('Login exitoso:', result.output);
// Procesar login
} else {
const newErrors: Record<string, string> = {};
result.issues.forEach(issue => {
if (issue.path) {
newErrors[issue.path[0].key] = issue.message;
}
});
setErrors(newErrors);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<input
name="email"
type="email"
placeholder="Email"
/>
{errors.email && <span>{errors.email}</span>}
</div>
<div>
<input
name="password"
type="password"
placeholder="Contraseña"
/>
{errors.password && <span>{errors.password}</span>}
</div>
<button type="submit">Iniciar Sesión</button>
</form>
);
}
Schemas Avanzados
1. Uniones y Discriminated Unions
import { object, string, literal, union } from 'valibot';
// Union simple
const StatusSchema = union([
literal('pending'),
literal('active'),
literal('inactive')
]);
// Discriminated union
const NotificationSchema = union([
object({
type: literal('email'),
email: string([email()]),
subject: string()
}),
object({
type: literal('sms'),
phone: string(),
message: string()
}),
object({
type: literal('push'),
token: string(),
title: string(),
body: string()
})
]);
2. Transformaciones
import { string, transform, trim, toLowerCase } from 'valibot';
// Transformación simple
const emailSchema = transform(
string([email()]),
(value) => value.toLowerCase().trim()
);
// Múltiples transformaciones
const usernameSchema = string([
transform(trim()),
transform(toLowerCase()),
minLength(3)
]);
3. Validaciones Personalizadas
import { string, custom } from 'valibot';
// Validador personalizado
const strongPasswordSchema = string([
minLength(8),
custom((value) => {
const hasUpperCase = /[A-Z]/.test(value);
const hasLowerCase = /[a-z]/.test(value);
const hasNumbers = /\d/.test(value);
const hasSpecialChar = /[!@#$%^&*]/.test(value);
return hasUpperCase && hasLowerCase && hasNumbers && hasSpecialChar;
}, 'La contraseña debe contener mayúsculas, minúsculas, números y caracteres especiales')
]);
Inferencia de Tipos
import { object, string, number, type Input, type Output } from 'valibot';
const UserSchema = object({
id: number(),
name: string(),
email: string([email()])
});
// Inferir tipos de entrada y salida
type UserInput = Input<typeof UserSchema>;
type UserOutput = Output<typeof UserSchema>;
// Usar los tipos
function createUser(data: UserInput): UserOutput {
return parse(UserSchema, data);
}
Comparación con Otras Bibliotecas
Valibot vs Zod
// Zod
import { z } from 'zod';
const schema = z.object({
name: z.string().min(2)
});
// Valibot
import { object, string, minLength } from 'valibot';
const schema = object({
name: string([minLength(2)])
});
Ventajas de Valibot:
- Bundle size mucho menor
- Modular y tree-shakeable
- API más funcional
Ventajas de Zod:
- Ecosistema más maduro
- Más características built-in
- Mayor adopción comunitaria
Mejores Prácticas
1. Organización de Esquemas
// schemas/user.ts
import { object, string, email, minLength } from 'valibot';
export const CreateUserSchema = object({
name: string([minLength(2)]),
email: string([email()]),
password: string([minLength(8)])
});
export const UpdateUserSchema = partial(CreateUserSchema);
2. Reutilización de Validadores
// validators/common.ts
import { string, minLength, regex } from 'valibot';
export const passwordValidator = string([
minLength(8, 'Mínimo 8 caracteres'),
regex(/[A-Z]/, 'Debe contener al menos una mayúscula'),
regex(/[a-z]/, 'Debe contener al menos una minúscula'),
regex(/[0-9]/, 'Debe contener al menos un número')
]);
// Usar en múltiples esquemas
const LoginSchema = object({
email: string([email()]),
password: passwordValidator
});
3. Manejo de Errores
import { safeParse, flatten } from 'valibot';
function validateData(data: unknown) {
const result = safeParse(UserSchema, data);
if (!result.success) {
const errors = flatten(result.issues);
console.error('Errores de validación:', errors);
return { success: false, errors };
}
return { success: true, data: result.output };
}
Conclusión
Valibot es una excelente opción para proyectos que requieren validación de esquemas con un enfoque en el rendimiento y el tamaño del bundle. Su diseño modular y su API funcional lo hacen ideal para aplicaciones modernas donde cada KB cuenta.
Recursos Adicionales
En el próximo tutorial, exploraremos casos de uso más avanzados y cómo integrar Valibot con diferentes frameworks y bibliotecas.