Record en TypeScript: analicemos en la práctica
\n\nImagina que estás escribiendo una aplicación para aprender palabras en inglés. Necesitas almacenar traducciones: cat → gato, dog → perro. ¿Cómo tipificar esto correctamente en TypeScript? Puedes crear una interfaz, pero ¿qué pasa si las claves no se conocen de antemano? ¿O si hay demasiadas? Aquí es donde Record viene al rescate: uno de los tipos utilitarios más útiles, pero a menudo subestimados.
En este artículo, analizaremos qué es el tipo Record en TypeScript, con ejemplos reales que podrás aplicar de inmediato en tus proyectos. Sin teoría aburrida, solo práctica.
\n\n¿Qué es Record en TypeScript? En palabras sencillas
\n\nRecord<K, V> es un tipo utilitario incorporado que crea un objeto donde todas las claves son del tipo K y todos los valores son del tipo V.
Piensa en él como un diccionario tipificado o un mapa con un conjunto fijo de claves.
La sintaxis básica se ve así:
\n\n// Objeto normal\nconst userRoles: Record<string, string> = {\n admin: 'Administrador',\n user: 'Usuario',\n guest: 'Invitado'\n};\n\nAquí, Record<string, string> significa: "Un objeto donde las claves son cadenas y los valores también son cadenas". Simple y claro.
¿Por qué Record es mejor que una interfaz normal?
\n\n- \n
- Flexibilidad de claves: Puedes definir un conjunto específico de claves mediante un tipo unión. \n
- Concisión: No necesitas describir cada campo manualmente. \n
- Seguridad: TypeScript verificará que solo uses las claves permitidas. \n
Record vs objeto simple: ejemplo ilustrativo
\n\nSupongamos que tenemos estados de pedido: pending, shipped, delivered. Sin Record, tendrías que escribir una interfaz con tres campos:
interface OrderStatusMap {\n pending: string;\n shipped: string;\n delivered: string;\n}\n\nconst statusDescriptions: OrderStatusMap = {\n pending: 'Pendiente de procesamiento',\n shipped: 'Enviado',\n delivered: 'Entregado'\n};\n\nY con Record, es más compacto y claro:
\n\ntype OrderStatus = 'pending' | 'shipped' | 'delivered';\n\nconst statusDescriptions: Record<OrderStatus, string> = {\n pending: 'Pendiente de procesamiento',\n shipped: 'Enviado',\n delivered: 'Entregado'\n};\n\nAdemás: si intentas agregar cancelled al objeto, TypeScript te señalará el error de inmediato: ese estado no existe en el tipo unión.
Top 5 ejemplos prácticos de uso de Record
\n\nVeamos dónde Record realmente simplifica la vida.
\n\n1. Configuración de la aplicación
\nAlmacena configuraciones con claves conocidas, pero diferentes tipos de valores:
\n\ntype ConfigKeys = 'apiUrl' | 'timeout' | 'retryCount';\ntype ConfigValue = string | number | boolean;\n\nconst appConfig: Record<ConfigKeys, ConfigValue> = {\n apiUrl: 'https://api.example.com',\n timeout: 5000,\n retryCount: 3\n};\n\n2. Mapeo de enum o constantes
\nA menudo es necesario asociar un código con su nombre legible:
\n\nenum HttpStatus {\n OK = 200,\n NotFound = 404,\n Error = 500\n}\n\nconst statusMessages: Record<HttpStatus, string> = {\n [HttpStatus.OK]: 'Todo bien',\n [HttpStatus.NotFound]: 'No encontrado',\n [HttpStatus.Error]: 'Error del servidor'\n};\n\n3. Formularios y validación
\nRecord es ideal para almacenar errores de validación por campo:
\n\ntype FormFields = 'email' | 'password' | 'name';\ntype ValidationErrors = Record<FormFields, string | null>;\n\nconst errors: ValidationErrors = {\n email: 'Correo electrónico no válido',\n password: null,\n name: 'El nombre es obligatorio'\n};\n\n4. Caché de datos
\nSimulación de un caché con claves de identificación:
\n\ntype UserI