TypeScript de Cero a Experto / Utility types
Record: construir mapas tipados
Partial, Pick y Omit transforman tipos que ya tienes. Record<K, V> hace algo
distinto: CONSTRUYE un tipo de objeto desde cero —uno cuyas claves son de tipo K y
cuyos valores son de tipo V—. Es el tipo de todo diccionario, mapa o índice, y ya
lo usaste de refilón para los totales por categoría. Hoy lo dominas.
El casillero etiquetado
Record<K, V>: la forma básica
Describe un objeto con claves de tipo K y valores de tipo V:
// Record<string, number> = un objeto de claves-texto con valores-número
type Totales = Record<string, number>;
const porCategoria: Totales = {
comida: 45000,
transporte: 8000,
ocio: 25000,
};
porCategoria.comida.toFixed(0); // ✓ los valores son number
// equivale a escribir { [clave: string]: number } (index signature),
// pero Record es más legible y componible:
type Config = Record<string, boolean>;
const flags: Config = { oscuro: true, beta: false };Record<string, number> es el tipo de cualquier diccionario "texto → número":
totales, conteos, cachés. Es equivalente a la vieja "index signature" { [k: string]: number }, pero se lee mejor y se combina con otros utility types con naturalidad.
Ya lo usaste en el módulo 5 y en los retos —ahora sabes exactamente qué es.
El poder real: claves de unión literal
Aquí Record brilla. Si las claves son una UNIÓN DE LITERALES (módulo 2), TS exige
que estén TODAS —un mapa exhaustivo, imposible de dejar incompleto:
type Categoria = "comida" | "transporte" | "ocio";
// Record<Categoria, number> exige las TRES claves, ni una más ni una menos:
const presupuesto: Record<Categoria, number> = {
comida: 300000,
transporte: 100000,
ocio: 80000,
};
// si olvidas 'ocio': ❌ Property 'ocio' is missing
// si agregas 'cripto': ❌ 'cripto' does not exist in type
// caso real: un mapa de color por estado, garantizado completo
type Estado = "activo" | "pausado" | "cerrado";
const colores: Record<Estado, string> = {
activo: "verde",
pausado: "ámbar",
cerrado: "gris",
};
// el día que agregues un estado a la unión, TS te obliga a darle su color aquí.Esto es exhaustividad (como el never del módulo 4, pero para objetos):
Record<Estado, string> GARANTIZA que definiste un color para cada estado posible. Y
si mañana agregas un estado a la unión Estado, TS marca el objeto colores en
rojo hasta que le des su color. Mapas que no pueden quedar incompletos —oro puro para
tablas de configuración.
Quieres un objeto que tenga OBLIGATORIAMENTE un mensaje de texto para cada uno de los estados 'ok' | 'error' | 'pendiente', sin que puedas olvidar ninguno. ¿Qué tipo lo garantiza?
Mini-reto
Crea un mapa a prueba de olvidos: 1) define type Dia = "lun" | "mar" | "mie" | "jue" | "vie"; 2) declara const horas: Record<Dia, number> con las horas trabajadas cada
día (TS te obliga a poner los cinco); 3) prueba a borrar un día y a agregar "sab",
y observa los dos errores distintos. Sientes cómo la unión literal + Record
garantiza completitud.
Qué sigue
Has derivado tipos de otros tipos. El último grupo de utility types deriva de
FUNCIONES y PROMESAS: ReturnType saca lo que una función devuelve, Parameters sus
argumentos, y Awaited desenvuelve lo que resuelve una promesa. Con ellos, tus tipos
siguen a tu código automáticamente.