Skip to content

Lección 91: keyof, typeof y Lookup Types

🎯 Objetivo: Dominar los operadores keyof, typeof y los lookup types (acceso indexado) para crear tipos derivados de forma dinámica.


🧠 Concepto

keyof toma un tipo y devuelve una unión de sus claves (nombres de propiedades).

💻 Ejemplo

type Persona = {
nombre: string;
edad: number;
email: string;
};
type ClavesPersona = keyof Persona;
// ⚡ "nombre" | "edad" | "email"
const k1: ClavesPersona = "nombre"; // ✅
const k2: ClavesPersona = "edad"; // ✅
const k3: ClavesPersona = "apellido"; // ❌ Error

Esto es increíblemente útil para restringir qué valores puede tomar un parámetro a las claves reales de un tipo.

function obtenerPropiedad<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const persona: Persona = { nombre: "Ana", edad: 30, email: "ana@mail.com" };
const nombre = obtenerPropiedad(persona, "nombre"); // string
const edad = obtenerPropiedad(persona, "edad"); // number
// obtenerPropiedad(persona, "apellido"); // ❌ Error: no es clave de Persona

🧠 Aplicación real: APIs de acceso seguro a propiedades, validación de formularios, selectores de estado.


typeof en TypeScript (en contexto de tipo) captura el tipo de una variable o expresión en tiempo de compilación.

const config = {
api: "https://api.example.com",
timeout: 5000,
retries: 3,
};
type TipoConfig = typeof config;
// {
// api: string;
// timeout: number;
// retries: number;
// }
function iniciar(cfg: TipoConfig) { /* ... */ }
iniciar({ api: "...", timeout: 2000, retries: 1 }); // ✅

⚠️ No confundir con el typeof de JavaScript (que evalúa en tiempo de ejecución). En contexto de tipo, TypeScript lo interpreta en compilación.

function sumar(a: number, b: number): number {
return a + b;
}
type TipoSumar = typeof sumar;
// (a: number, b: number) => number
type RetornoSumar = ReturnType<typeof sumar>;
// number
type ParametrosSumar = Parameters<typeof sumar>;
// [a: number, b: number]

3. Lookup Types — Acceso indexado Tipo['propiedad']

Section titled “3. Lookup Types — Acceso indexado Tipo['propiedad']”

También llamados indexed access types. Permiten acceder al tipo de una propiedad específica usando la sintaxis de corchetes.

type Persona = {
nombre: string;
direccion: {
calle: string;
ciudad: string;
};
hobbies: string[];
};
type TipoNombre = Persona["nombre"]; // string
type TipoDireccion = Persona["direccion"]; // { calle: string; ciudad: string }
type TipoHobbies = Persona["hobbies"]; // string[]
type TipoItemHobby = Persona["hobbies"][number]; // string (acceso a item del array)
type Persona = { nombre: string; edad: number; activo: boolean };
type NombreOEdad = Persona["nombre" | "edad"];
// string | number
type CualquierValor = Persona[keyof Persona];
// string | number | boolean
type RespuestaAPI = {
data: {
usuario: {
id: number;
perfil: {
avatar: string;
bio: string;
};
};
};
};
type BioUsuario = RespuestaAPI["data"]["usuario"]["perfil"]["bio"];
// string

type Eventos = {
click: { x: number; y: number };
keydown: { key: string };
submit: { formData: FormData };
};
function emitirEvento<E extends keyof Eventos>(
evento: E,
datos: Eventos[E]
) {
console.log(`Evento ${evento}:`, datos);
}
emitirEvento("click", { x: 10, y: 20 }); // ✅
emitirEvento("keydown", { key: "Enter" }); // ✅
emitirEvento("click", { key: "x" }); // ❌ Error: no coincide con click
const colores = {
primary: "#007bff",
secondary: "#6c757d",
success: "#28a745",
danger: "#dc3545",
} as const;
type ColorKey = keyof typeof colores;
// "primary" | "secondary" | "success" | "danger"
type ColorValue = typeof colores[ColorKey];
// "#007bff" | "#6c757d" | "#28a745" | "#dc3545"

📝 Resumen: keyof extrae claves como unión, typeof captura tipos de valores existentes, y los lookup types permiten navegar por la estructura de tipos. Combinados, permiten escribir código genérico y reutilizable con type safety absoluto.