Historia de la pregunta
TypeScript fue diseñado desde el principio para una tipificación estricta de objetos y para escribir código más predecible en JavaScript. Uno de los instrumentos para garantizar la seguridad al acceder a las propiedades de los objetos es el operador keyof, que apareció en TypeScript 2.1. Permite crear tipos que representan un conjunto de claves (cadenas y simbólicas) disponibles en el tipo de objeto declarado.
Problema
En JavaScript puro, las propiedades de un objeto pueden ser consultadas con cualquier cadena, y si hay un error, se obtendrá undefined o un error que solo se encontrará en tiempo de ejecución. Sin una tipificación estricta, es fácil cometer un error tipográfico o olvidar actualizar una cadena clave durante el refactorizado. Además, a menudo se requiere construir una función que solo acepte claves correctas de un objeto o tipo específico.
Solución
El operador keyof crea un tipo de unión de todas las claves del tipo. Con él, se pueden limitar las claves permitidas, aumentar la seguridad de la API (por ejemplo, para funciones getter/setter) y crear tipos utilitarios genéricos.
Ejemplo de código:
type User = { name: string; age: number; active: boolean }; type UserKey = keyof User; // "name" | "age" | "active" function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const user: User = { name: 'Tom', age: 33, active: true }; const age = getProp(user, 'age'); // edad tipo number
Características clave:
¿Qué devuelve keyof para un arreglo y se pueden obtener los índices?
keyof para un arreglo devuelve los tipos de las claves del objeto, que en realidad es lo que el arreglo es en JS. Normalmente son cadenas de índices y propiedades especiales del arreglo.
Ejemplo de código:
type A = keyof number[]; // "length" | "toString" | "pop" | ... | number
¿Puede keyof devolver claves de tipos de unión?
Sí, keyof de un tipo de unión devuelve la intersección de las claves de ambos objetos, no su unión.
Ejemplo de código:
type A = {a: string, b: number } type B = {b: number, c: boolean } type C = keyof (A | B); // "b"
¿Qué ocurre si la propiedad de un objeto es opcional? ¿Admite keyof "?"?
Sí, las propiedades opcionales también están incluidas en el tipo resultante de claves, pero esto no significa que la propiedad deba estar presente en el objeto en tiempo de ejecución.
Ejemplo de código:
type D = { a: string; b?: number }; type DK = keyof D; // "a" | "b"
Se escribe una función getProperty(obj, key) con una clave de tipo string, se llama con una clave inexistente — el error aparece solo en tiempo de ejecución.
Ventajas:
Desventajas:
Se utilizan genéricos: getProperty<T, K extends keyof T>(), el tipo key está estrictamente limitado a las claves de la estructura.
Ventajas:
Desventajas: