¿Existe un `valueof` similar a `keyof` en TypeScript? Optimización y rendimiento
\n\n¿Alguna vez has escrito en TypeScript y te has sorprendido pensando: «Tengo keyof para las claves, ¿y dónde está valueof para los valores?» Si es así, no estás solo. Esta pregunta en Stack Overflow ha acumulado miles de visitas, y hoy la analizaremos de principio a fin. Pero no solo como teoría abstracta, sino con un enfoque en la optimización y el rendimiento de tu código. ¡Vamos allá!
¿Por qué existe `keyof` y no `valueof`?
\n\nEn TypeScript existe el tipo utilitario incorporado keyof. Toma un tipo de objeto y devuelve la unión de todas sus claves:
type Person = {\n name: string;\n age: number;\n isActive: boolean;\n};\n\ntype PersonKeys = keyof Person; // "name" | "age" | "isActive"\n\n¿Y qué pasa con los valores? Queremos obtener string | number | boolean del mismo tipo. En la biblioteca estándar de TypeScript no existe tal cosa. ¿Por qué? Porque valueof no es simplemente una «operación inversa». Un objeto puede tener muchas claves con los mismos tipos, y necesitamos decidir cómo unirlos. ¡Pero eso no significa que no podamos escribir nuestro propio valueof!
Creando nuestro propio `ValueOf`
\n\nLa forma más sencilla es usar el tipo de acceso por índice (indexed access type) en combinación con keyof:
type ValueOf<T> = T[keyof T];\n\ntype PersonValues = ValueOf<Person>; // string | number | boolean\n\n¡Eso es todo! Acabamos de crear el tipo genérico ValueOf que funciona como valueof. Pero profundicemos más: ¿cómo afecta esto al rendimiento y cómo usarlo con inteligencia?
Optimización: cuando `ValueOf` evita la duplicación
\n\nImagina que tienes un objeto de configuración con decenas de campos. Quieres escribir una función que acepte cualquier valor de ese objeto. Sin ValueOf, tendrías que enumerar los tipos manualmente:
type Config = {\n apiUrl: string;\n timeout: number;\n retries: number;\n debug: boolean;\n};\n\n// Mal: duplicación de tipos\nfunction setConfigValue(key: string, value: string | number | boolean) {\n // ...\n}\n\nY ahora con ValueOf:
// Bien: captura automáticamente todos los tipos de valores\nfunction setConfigValue(key: keyof Config, value: ValueOf<Config>) {\n // TypeScript sabe que value solo puede ser string | number | boolean\n}\n\nEsto no solo reduce el código, sino que lo hace autodocumentado. Si agregas un nuevo campo a Config, TypeScript capturará automáticamente el nuevo tipo. Menos errores, más productividad en el desarrollo.
`ValueOf` avanzado con tipos condicionales
\n\nA veces es necesario obtener los valores solo de ciertas claves. Por ejemplo, todos los valores numéricos. Aquí es donde los tipos condicionales (conditional types) vienen al rescate:
\n\ntype NumericValues<T> = {\n [K in keyof T]: T[K] extends number ? T[K] : never;\n}[keyof T];\n\ntype ConfigNumeric = NumericValues<Config>; // number (timeout | retries)\n\nEste truco es especialmente útil cuando se trabaja con tipos grandes: puedes filtrar solo los valores necesarios y evitar comprobaciones innecesarias en tiempo de ejecución. La optimización a nivel de tipos es rendimiento gratuito, porque los tipos desaparecen en la compilación.
\n\nRendimiento en tiempo de ejecución: ¿es necesario?
\n\nUn punto importante: ValueOf es una construcción puramente de tipos. No genera ningún código JavaScript. Pero su uso correcto puede aumentar indirectamente el rendimiento de tu aplicación:
- \n
- Menos errores — menos tiempo de depuración. \n
- Tipado más estricto — el compilador detecta \n