emptyKeys
Paquete: @tiendana/utils
Identifica qué propiedades de un objeto tienen valores vacíos (null, undefined, '', NaN, []) entre un conjunto de claves especificadas.
Características
✅ Filtra propiedades vacías de un objeto
✅ Trabaja con lista específica de claves
✅ Usa hasValue internamente para validación
✅ Retorna array de strings (nombres de propiedades)
✅ Útil para validación de formularios
✅ Identificación rápida de campos faltantes
Firma
function emptyKeys(obj: any, keys: string[]): string[]
Parámetros
| Parámetro | Tipo | Descripción | Requerido |
|---|---|---|---|
obj | any | Objeto a validar | ✅ |
keys | string[] | Array de nombres de propiedades a verificar | ✅ |
Retorno
Tipo: string[]
Array con los nombres de las propiedades que tienen valores vacíos.
Ejemplos de Uso
Validación Básica
import { emptyKeys } from '@tiendana/utils';
const user = {
name: 'Juan',
email: '',
phone: null,
age: 30
};
emptyKeys(user, ['name', 'email', 'phone']);
// ['email', 'phone']
Validación de Formulario
interface RegistrationForm {
firstName: string;
lastName: string;
email: string;
phone: string;
terms: boolean;
}
function validateRegistration(form: RegistrationForm): string[] {
const requiredFields = ['firstName', 'lastName', 'email'];
return emptyKeys(form, requiredFields);
}
const formData = {
firstName: 'Juan',
lastName: '',
email: 'juan@example.com',
phone: '',
terms: false
};
const missing = validateRegistration(formData);
// ['lastName']
if (missing.length > 0) {
console.error(`Campos requeridos vacíos: ${missing.join(', ')}`);
}
Validación con Mensajes Personalizados
const fieldLabels: Record<string, string> = {
firstName: 'Nombre',
lastName: 'Apellido',
email: 'Correo Electrónico',
phone: 'Teléfono'
};
function getValidationErrors(data: any, required: string[]): string[] {
const empty = emptyKeys(data, required);
return empty.map(key => `${fieldLabels[key]} es requerido`);
}
const errors = getValidationErrors(formData, ['firstName', 'lastName', 'email']);
// ['Apellido es requerido']
Validación de Múltiples Secciones
interface CheckoutForm {
// Billing
billingName: string;
billingAddress: string;
billingCity: string;
// Shipping
shippingName: string;
shippingAddress: string;
shippingCity: string;
// Payment
cardNumber: string;
cardExpiry: string;
cardCvv: string;
}
function validateCheckout(form: CheckoutForm) {
const billingFields = ['billingName', 'billingAddress', 'billingCity'];
const shippingFields = ['shippingName', 'shippingAddress', 'shippingCity'];
const paymentFields = ['cardNumber', 'cardExpiry', 'cardCvv'];
return {
billing: emptyKeys(form, billingFields),
shipping: emptyKeys(form, shippingFields),
payment: emptyKeys(form, paymentFields)
};
}
const validation = validateCheckout(checkoutData);
// {
// billing: [],
// shipping: ['shippingCity'],
// payment: ['cardCvv']
// }
Validación Condicional
function validateUserProfile(user: any, role: 'admin' | 'user'): string[] {
const baseFields = ['name', 'email'];
const adminFields = role === 'admin'
? [...baseFields, 'department', 'permissions']
: baseFields;
return emptyKeys(user, adminFields);
}
validateUserProfile(adminUser, 'admin');
// ['department'] - falta department para admin
validateUserProfile(regularUser, 'user');
// [] - user solo necesita name y email
Verificar Progreso de Formulario
function getFormProgress(data: any, allFields: string[]): number {
const empty = emptyKeys(data, allFields);
const filled = allFields.length - empty.length;
return Math.round((filled / allFields.length) * 100);
}
const progress = getFormProgress(formData, [
'firstName', 'lastName', 'email', 'phone', 'address', 'city'
]);
// 67: solo lastName y phone existen y están vacíos; address y city no
// existen en formData, por lo que emptyKeys no los reporta y cuentan como completos
Validación de API Request
interface CreateProductRequest {
name: string;
price: number;
category: string;
description: string;
sku: string;
}
function validateProductRequest(req: Partial<CreateProductRequest>): {
valid: boolean;
missing: string[];
} {
const requiredFields = ['name', 'price', 'category', 'sku'];
const missing = emptyKeys(req, requiredFields);
return {
valid: missing.length === 0,
missing
};
}
const validation = validateProductRequest({
name: 'Product Name',
price: 0, // 0 es válido (hasValue retorna true)
category: '',
sku: 'SKU-123'
});
// { valid: false, missing: ['category'] }
// validateProductRequest({ name: 'x' }) → { valid: true, missing: [] }: los campos ausentes no se reportan
Resaltar Campos Vacíos en UI
interface FormField {
name: string;
label: string;
value: any;
error?: string;
}
function markEmptyFields(
fields: FormField[],
data: any
): FormField[] {
const fieldNames = fields.map(f => f.name);
const empty = emptyKeys(data, fieldNames);
return fields.map(field => ({
...field,
error: empty.includes(field.name)
? `${field.label} es requerido`
: undefined
}));
}
const formFields = [
{ name: 'name', label: 'Nombre', value: formData.name },
{ name: 'email', label: 'Email', value: formData.email }
];
const fieldsWithErrors = markEmptyFields(formFields, formData);
// Campos con error: 'email es requerido' si email está vacío
Validación antes de Enviar
function canSubmitForm(data: any, requiredFields: string[]): boolean {
return emptyKeys(data, requiredFields).length === 0;
}
const submitButton = document.querySelector('#submit-btn');
if (canSubmitForm(formData, ['name', 'email', 'terms'])) {
submitButton.disabled = false;
} else {
submitButton.disabled = true;
}
Casos de Uso Comunes
- Validación de formularios: Identificar campos requeridos no completados
- Progreso de formulario: Calcular porcentaje de completitud
- Validación de API: Detectar campos presentes pero vacíos (los ausentes no se reportan)
- UI highlighting: Marcar campos vacíos con estilos de error
- Prevención de envío: Deshabilitar botón submit si faltan campos
- Mensajes de error: Generar mensajes específicos por campo vacío
- Validación condicional: Validar diferentes campos según contexto
Valores Considerados Vacíos
La función usa hasValue internamente, por lo que considera vacíos:
nullundefined''(string vacío)NaN[](array vacío)
NO considera vacíos:
0(número cero)false(booleano){}(objeto vacío)
const data = {
count: 0, // ✅ No vacío
active: false, // ✅ No vacío
items: [], // ❌ Vacío (un array sin elementos)
config: {}, // ✅ No vacío
name: '', // ❌ Vacío
email: null, // ❌ Vacío
phone: undefined // ❌ Vacío
};
emptyKeys(data, ['count', 'active', 'items', 'config', 'name', 'email', 'phone']);
// ['items', 'name', 'email', 'phone']
Notas Técnicas
- Performance: O(n) donde n es el número de keys a verificar
- Filter-based: Usa
Array.filter()para identificar keys vacías - Type-agnostic: Acepta
anypara flexibilidad en validación - Dependencia: Requiere
hasValuede@tiendana/utils - No modifica objeto: Solo lee propiedades, no las modifica
- Keys no existentes: Solo se revisan las claves que existen en el objeto; una clave de
keysqueobjno tiene nunca se reporta
Diferencias con hasValue
import { hasValue, emptyKeys } from '@tiendana/utils';
// hasValue: Valida UN valor
hasValue(user.email); // false
// emptyKeys: Valida MÚLTIPLES propiedades
emptyKeys(user, ['email', 'phone', 'name']); // ['email', 'phone']
Limitaciones
{} pasa como valor presente, porque hasValue solo mira la longitud de los arrays:
const data = {
tags: [],
config: {}
};
emptyKeys(data, ['tags', 'config']);
// ['tags'] ← el array vacío se reporta, el objeto vacío no
// Si necesitas validar también objetos vacíos:
function isEmptyValue(value: any): boolean {
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
return Object.keys(value).length === 0;
}
return !hasValue(value);
}
La función itera las claves del objeto y las filtra contra keys. Si una clave de keys no existe en el objeto, no aparece en el resultado:
const user = { name: 'Juan', phone: '' };
emptyKeys(user, ['name', 'email', 'phone']);
// ['phone'] ← 'email' no existe en el objeto y se ignora
Para exigir campos obligatorios, inicializa todos los campos en el objeto (por ejemplo con null).