🛡️ Yup Cheatsheet Completo 🛡️

Yup es una librería de JavaScript para la validación de esquemas. Te permite definir la forma (estructura y reglas de validación) de tus datos y luego validar esos datos contra el esquema. Es comúnmente utilizada en aplicaciones web para la validación de formularios, pero puede usarse para cualquier tipo de validación de datos.


1. 🌟 Conceptos Clave


2. 🛠️ Configuración Inicial

  1. Instalación:
    npm install yup
    # o
    yarn add yup
  2. Importación:
    import * as yup from 'yup';
    // O importaciones específicas si usas tree-shaking
    // import { string, number, object, boolean } from 'yup';

3. 🧩 Tipos de Esquemas Básicos

Cada método en yup (ej. yup.string(), yup.number()) devuelve un objeto de esquema sobre el cual puedes encadenar reglas de validación.

3.1. Primitivos


4. 📦 Tipos de Esquemas Compuestos

4.1. yup.object(shape)

Define la forma de un objeto, donde las claves son los nombres de las propiedades y los valores son otros esquemas Yup.

const userSchema = yup.object({
  id: yup.string().uuid().required(),
  name: yup.string().min(3, "El nombre debe tener al menos 3 caracteres").required("El nombre es obligatorio"),
  email: yup.string().email("Email inválido").nullable(), // Puede ser null o string
  age: yup.number().integer("La edad debe ser un número entero").positive("La edad debe ser un número positivo").optional(), // Opcional (puede ser undefined)
  isActive: yup.boolean().default(false),
});

4.2. yup.array(elementType)

Define un array de elementos que deben coincidir con el elementType esquema.

const tagsSchema = yup.array(yup.string()).min(1, "Debe tener al menos un tag");

const productSchema = yup.object({
  name: yup.string().required(),
  price: yup.number().positive().required(),
  tags: tagsSchema, // Usando el esquema de array definido arriba
  photos: yup.array(yup.object({ // Array de objetos
    url: yup.string().url().required(),
    caption: yup.string().optional(),
  })).min(1, "Debe tener al menos una foto").required(),
});

4.3. yup.mixed()

Un esquema para un valor de tipo mixto (cualquier tipo).


5. 🚀 Validación (Parsing)

5.1. schema.validate(data, options)

import * as yup from 'yup';

const loginSchema = yup.object({
  username: yup.string().required(),
  password: yup.string().min(6).required(),
});

async function validateLoginForm(formData) {
  try {
    const validData = await loginSchema.validate(formData, { abortEarly: false }); // Captura todos los errores
    console.log('Datos válidos:', validData);
    return { success: true, data: validData };
  } catch (error) {
    if (error.name === 'ValidationError') {
      console.error('Errores de validación:', error.errors); // Array de mensajes de error
      // error.inner es un array de ValidationError con detalles por campo
      const errors = error.inner.reduce((acc, currentError) => {
        acc[currentError.path] = currentError.message;
        return acc;
      }, {});
      return { success: false, errors };
    }
    console.error('Error inesperado:', error);
    return { success: false, error: 'Unhandled error' };
  }
}

// Ejemplo de uso
validateLoginForm({ username: 'john_doe', password: '123' })
  .then(result => console.log('Resultado de validación 1:', result));

validateLoginForm({ username: 'short', password: '123' })
  .then(result => console.log('Resultado de validación 2:', result));

5.2. schema.isValid(data, options)

const isValid = await loginSchema.isValid({ username: 'test', password: 'password123' });
console.log('¿Es válido?:', isValid); // true

5.3. schema.validateSync(data, options)

5.4. schema.isValidSync(data, options)


6. ✍️ Validación Personalizada (test, when)

6.1. schema.test(name, message, testFn)

Define una regla de validación personalizada.

const passwordSchema = yup.string()
  .min(8, "La contraseña debe tener al menos 8 caracteres")
  .test('has-uppercase', 'La contraseña debe contener al menos una mayúscula', function(value) {
    return /[A-Z]/.test(value);
  })
  .test('has-digit', 'La contraseña debe contener al menos un número', (value) => {
    return /[0-9]/.test(value);
  });

const confirmPasswordSchema = yup.string()
  .required("Confirma tu contraseña")
  .test('passwords-match', 'Las contraseñas no coinciden', function(value) {
    // Accede al valor de 'password' usando `this.parent.password` o `this.path`
    return value === this.parent.password;
  });

const signupSchema = yup.object({
  password: passwordSchema,
  confirmPassword: confirmPasswordSchema,
});

6.2. schema.when(keys, builder) (Validación Condicional)

Aplica reglas condicionalmente basándose en el valor de otros campos.

const shippingSchema = yup.object({
  shippingMethod: yup.string().required().oneOf(['pickup', 'delivery']),
  deliveryAddress: yup.string().when('shippingMethod', {
    is: 'delivery',
    then: (schema) => schema.required('La dirección de entrega es obligatoria para envíos a domicilio'),
    otherwise: (schema) => schema.optional(),
  }),
  // También se puede usar `is: (val) => val === 'delivery'`
  // Con múltiples campos: yup.string().when(['field1', 'field2'], ([field1, field2], schema) => {...})
});

7. ↔️ Transformaciones

Los métodos de transformación (.transform()) modifican el valor del esquema durante el proceso de validación.

const nameSchema = yup.string()
  .trim() // Elimina espacios en blanco
  .lowercase() // Convierte a minúsculas
  .transform(value => value === '' ? null : value) // Convierte cadena vacía a null
  .nullable()
  .required('El nombre es requerido');

const ageSchema = yup.number()
  .transform(value => (isNaN(value) ? undefined : value)) // Coerce NaN a undefined
  .required('La edad es requerida');

const formSchema = yup.object({
  name: nameSchema,
  age: ageSchema,
});

8. 🟦 Inferencia de Tipos (TypeScript)

Yup tiene una excelente inferencia de tipos con TypeScript.

import * as yup from 'yup';

const userSchema = yup.object({
  name: yup.string().required(),
  age: yup.number().required(),
  email: yup.string().email().optional(),
});

// Inferir el tipo de los datos validados
type User = yup.InferType<typeof userSchema>;

// User es ahora:
// {
//   name: string;
//   age: number;
//   email?: string | undefined;
// }

const data: User = {
  name: 'Jane Doe',
  age: 28,
  // email: 'jane@example.com' // Opcional
};

9. 🚀 Integración con React Hook Form

Yup es un resolver de validación muy común para React Hook Form.

  1. Instalación:
    npm install @hookform/resolvers yup
  2. Uso:
    import React from 'react';
    import { useForm } from 'react-hook-form';
    import { yupResolver } from '@hookform/resolvers/yup';
    import * as yup from 'yup';
    
    const schema = yup.object({
      firstName: yup.string().required('El nombre es obligatorio'),
      age: yup.number().positive('Debe ser positivo').integer('Debe ser un entero').required('La edad es obligatoria'),
      email: yup.string().email('Email inválido').required('El email es obligatorio'),
    }).required();
    
    function MyForm() {
      const { register, handleSubmit, formState: { errors } } = useForm({
        resolver: yupResolver(schema) // Aquí se integra Yup
      });
    
      const onSubmit = data =&gt; console.log(data);
    
      return (
        <form onSubmit={handleSubmit(onSubmit)}>
          <input {...register("firstName")} placeholder="Nombre" />
          <p>{errors.firstName?.message}</p>
    
          <input type="number" {...register("age")} placeholder="Edad" />
          <p>{errors.age?.message}</p>
    
          <input {...register("email")} placeholder="Email" />
          <p>{errors.email?.message}</p>
    
          <button type="submit">Enviar</button>
        </form>
      );
    }
    export default MyForm;

10. 💡 Buenas Prácticas y Consejos


Este cheatsheet te proporciona una referencia completa de Yup, cubriendo sus conceptos esenciales, la definición de esquemas para diferentes tipos de datos, técnicas de validación avanzada, transformaciones y la integración con React Hook Form, junto con buenas prácticas para un uso eficaz y robusto.