Skip to content

Validadores Integrados ​

QuickModel incluye 14 decoradores validadores listos para usar que ofrecen una API familiar al estilo de class-validator, implementados como wrappers delgados sobre @QRule. Sin dependencias adicionales: utilizan el mismo motor de reglas que impulsa toda la validación de QuickModel.

Importación ​

typescript
// Entry principal (todos los validadores junto al resto de QuickModel)
import { IsEmail, Min, IsNotEmpty } from 'quickmodel';

// Subpath tree-shakeable (incluye SOLO los validadores que importas)
import { IsEmail } from 'quickmodel/validators';

Validadores de cadena ​

@IsEmail() ​

Valida que el valor es una dirección de email sintácticamente correcta.

typescript
@IsEmail()
declare email: string;

@IsUrl() ​

Valida que el valor es una URL sintácticamente válida (usa el constructor nativo URL — acepta cualquier esquema válido).

typescript
@IsUrl()
declare sitioWeb: string;

@IsNotEmpty() ​

Valida que la cadena no está vacía ni contiene solo espacios en blanco.

typescript
@IsNotEmpty()
declare nombre: string;

@MinLength(n: number) ​

Valida que la cadena tiene al menos n caracteres.

typescript
@MinLength(3)
declare usuario: string;

@MaxLength(n: number) ​

Valida que la cadena tiene como máximo n caracteres.

typescript
@MaxLength(50)
declare bio: string;

@Matches(regex: RegExp) ​

Valida que la cadena coincide con la expresión regular indicada.

typescript
@Matches(/^[a-z0-9_]+$/)
declare handle: string;

@IsUuid() ​

Valida que el valor es un UUID válido (v1–v5).

typescript
@IsUuid()
declare id: string;

@IsDateString() ​

Valida que el valor es una cadena de fecha ISO 8601 válida.

typescript
@IsDateString()
declare fechaNacimiento: string;
// "2024-01-15T12:00:00Z" ✅   "no-es-fecha" ❌

Validadores numéricos ​

@Min(n: number) ​

Valida que el número es mayor o igual a n.

typescript
@Min(0)
declare edad: number;

@Max(n: number) ​

Valida que el número es menor o igual a n.

typescript
@Max(120)
declare edad: number;

@IsInt() ​

Valida que el valor es un entero (sin parte decimal).

typescript
@IsInt()
declare cantidad: number;
// 3 ✅   3.14 ❌

@IsPositive() ​

Valida que el valor es mayor que 0.

typescript
@IsPositive()
declare precio: number;

@IsNegative() ​

Valida que el valor es menor que 0.

typescript
@IsNegative()
declare penalizacion: number;

Validador de enumeración ​

@IsIn(values: unknown[]) ​

Valida que el valor es uno de los valores permitidos.

typescript
@IsIn(['admin', 'editor', 'viewer'])
declare rol: string;

Ejemplo completo ​

typescript
import {
	Quick,
	QModel,
	IsEmail,
	IsNotEmpty,
	MinLength,
	MaxLength,
	Min,
	Max,
	IsInt,
	IsPositive,
	IsIn,
} from 'quickmodel';

interface IUsuario {
	nombre: string;
	email: string;
	edad: number;
	rol: string;
}

@Quick()
class Usuario extends QModel<IUsuario> {
	@IsNotEmpty()
	@MinLength(2)
	@MaxLength(80)
	declare nombre: string;

	@IsEmail()
	declare email: string;

	@Min(18)
	@Max(120)
	@IsInt()
	declare edad: number;

	@IsIn(['admin', 'editor', 'viewer'])
	declare rol: string;
}

const user = new Usuario({
	nombre: 'A',
	email: 'malo',
	edad: 17.5,
	rol: 'hacker',
});
const { valid, errors } = user.$qCheckRules();
// valid: false
// errors: [
//   { field: 'nombre', message: 'Debe tener al menos 2 caracteres' },
//   { field: 'email',  message: 'Debe ser un email válido' },
//   { field: 'edad',   message: 'Debe ser al menos 18' },
//   { field: 'edad',   message: 'Debe ser un entero' },
//   { field: 'rol',    message: 'Debe ser uno de los valores permitidos' },
// ]

Apilado de validadores ​

Todos los validadores integrados se pueden apilar en la misma propiedad. Cada regla que falle se recoge de forma independiente.

typescript
@Min(0)
@Max(150)
@IsInt()
@IsPositive()
declare puntuacion: number;

Uso sin QModel ​

Los validadores integrados funcionan sobre cualquier clase plana, sin necesidad de extender QModel. Combínalos con qCheckRules del subpath /forms:

typescript
import { IsEmail, MinLength } from 'quickmodel/validators';
import { qCheckRules } from 'quickmodel/forms';

class FormularioContacto {
	@IsEmail()
	email = '';

	@MinLength(10)
	mensaje = '';
}

const form = new FormularioContacto();
form.email = 'hola@mundo.com';
form.mensaje = 'Hi';

const result = qCheckRules(form);
// { valid: false, errors: [{ field: 'mensaje', ... }] }

Decoradores TC39 ​

En modo TC39 (experimentalDecorators ausente o false), usa ! en lugar de declare:

typescript
@Quick()
class Usuario extends QModel<IUsuario> {
	@IsEmail()
	email!: string; // ← TC39: usa !

	@Min(18)
	edad!: number;
}

Todos los validadores de un vistazo ​

DecoradorValida
@IsEmail()Dirección de email válida
@IsUrl()URL sintácticamente válida (vía new URL())
@IsNotEmpty()Cadena no vacía ni solo espacios
@MinLength(n)Longitud de cadena ≥ n
@MaxLength(n)Longitud de cadena ≤ n
@Matches(regex)Cadena coincide con la RegExp indicada
@IsUuid()UUID válido (v1–v5)
@IsDateString()Cadena de fecha ISO 8601 válida
@Min(n)Número ≥ n
@Max(n)Número ≤ n
@IsInt()Entero (sin parte decimal)
@IsPositive()Número > 0
@IsNegative()Número < 0
@IsIn(values[])Valor entre los permitidos

Todos los validadores son wrappers sobre @QRule. Puedes combinarlos libremente con predicados @QRule personalizados en la misma propiedad.

Ver también ​

Rendimiento ​

⚡ Comparativa de rendimiento

Pasa el ratón sobre las barras para ver detalles

3k iteraciones con datos inválidos — obtener objetos de error categorizados. QuickModel validationReport(): retorna { valid, integrity[], rules: { valid, errors[] } } — dos categorías separadas: errores de tipo/coerción (integrity) y errores de lógica de negocio (@QRule). Zod safeParse(): array plano ZodError.issues, sin categorías. yup validateSync(abortEarly:false): ValidationError.errors plano. joi validate(abortEarly:false): array error.details plano. Solo QuickModel distingue fallos de integridad vs reglas en una sola llamada tipada.

QuickModel
657k ops/s
›› bastante más rápido
Zod
51k ops/s
joi
50k ops/s
yup
21k ops/s

No aplica en este escenario: TypeBox, arktype, valibot, class-validator, vest

← más lento       más rápido →