Lecciones del módulo (2/2)
Genéricos Fundamentales
Los Generics (programación genérica) son una de las características más potentes de TypeScript. Permiten escribir componentes, funciones e interfaces flexibles y reutilizables que pueden trabajar con diferentes tipos de datos, manteniendo la máxima seguridad de tipos (type safety) y evitando el uso de any.
Las Funciones Genéricas
Piensa en un generic como una variable para los tipos. Consideremos una función que devuelve el valor pasado como argumento:
function identity<T>(arg: T): T {
return arg;
}La letra T (abreviatura de Type) es un marcador de posición para el tipo. Cuando llamamos a identity, TypeScript captura el tipo del argumento pasado y establece automáticamente T a ese tipo:
const str = identity<string>('Hello'); // T è string
const num = identity(42); // T è number (inferito automaticamente!)Interfaces y Alias Genéricos
Los generics también se pueden aplicar a interfaces y alias de tipo para definir contenedores o estructuras de datos genéricas:
interface Box<T> {
content: T;
}
const stringBox: Box<string> = { content: 'TypeScript' };
const numberBox: Box<number> = { content: 42 };Múltiples Parámetros de Tipo
Podemos definir funciones o tipos que utilicen múltiples variables de tipo (ej. T y U):
function mergeObjects<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}Restricciones en los Generics (Generic Constraints)
A veces queremos limitar los tipos aceptados por un generic. Podemos usar la palabra clave extends para agregar una restricción (constraint).
Por ejemplo, si queremos que el tipo genérico tenga siempre una propiedad length (como cadenas o arrays):
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): void {
console.log(arg.length); // Sicuro! Sappiamo che arg ha 'length'
}
logLength('Hello'); // Valido
logLength([1, 2, 3]); // Valido
// logLength(42); // Errore: number non ha la proprietà length!Pruébalo tú
Ejercicio 1: Función Genérica Identity
Completa la función genérica identity de modo que acepte un parámetro value de tipo genérico T y lo devuelva sin modificaciones.
Mostrar pista
El tipo de retorno debe ser el mismo tipo genérico T del parámetro.
Solución disponible después de 3 intentos
Ejercicio 2: Contenedor Genérico Box
Define una interfaz genérica llamada Box que acepte un parámetro de tipo T y tenga una única propiedad llamada content de tipo T.
Mostrar pista
Usa la sintaxis interface Box<T> { content: T; }.
Solución disponible después de 3 intentos
Ejercicio 3: Restricción Genérica (Constraint)
Escribe una función genérica llamada getLength que acepte un parámetro arg. arg debe estar restringido a una interfaz que posea una propiedad length (número). La función debe devolver arg.length.
Mostrar pista
Declara la función como getLength<T extends HasLength>(arg: T): number y devuelve arg.length.
Solución disponible después de 3 intentos
Ejercicio 4: Pareja Genérica Pair
Define una interfaz genérica Pair<T, U> con dos propiedades: first de tipo T y second de tipo U. Después, crea una función genérica makePair que acepte first (de tipo T) y second (de tipo U) y devuelva un objeto que implemente Pair<T, U>.
Mostrar pista
Usa la sintaxis para dos parámetros genéricos Pair<T, U> y define makePair en consecuencia.
Solución disponible después de 3 intentos