Un genérico sin restricción acepta cualquier cosa:
TypeScript se queja: T podría ser un número, un booleano, cualquier cosa. No todos los tipos tienen .length.
Con extends le dices a TypeScript: "T no puede ser cualquier cosa, debe cumplir con esta forma":
T extends { length: number } significa: "T debe ser un tipo que tenga al menos una propiedad length de tipo number".
Puedes usar interfaces como restricción:
keyof devuelve una union de todas las claves (propiedades) de un tipo:
Esto es muy potente combinado con genéricos.
El ejemplo más clásico de keyof con genéricos:
Desglosemos la firma:
T es el tipo del objeto (se infiere como { nombre: string; edad: number; ciudad: string })K extends keyof T significa que K debe ser una de las claves de T ("nombre" | "edad" | "ciudad")T[K] es el tipo del valor en esa clave (si K es "nombre", T[K] es string)TypeScript te da autocompletado de las claves válidas y sabe el tipo exacto del retorno. No podrías lograr esto con any.
También puedes restringir a una union:
Combina restricciones encadenando con &:
Crea una función genérica obtenerPropiedad<T, K extends keyof T>(obj: T, key: K): T[K] que:
Las restricciones son lo que hace que los genéricos sean prácticos. Sin ellas, T es demasiado amplio para ser útil. Con ellas, T es flexible pero seguro.