Genéricos avanzados de TypeScript explicados con ejemplos
Los genéricos en TypeScript brindan una manera de crear componentes de código reutilizables y flexibles al trabajar con una variedad de tipos de datos. Los genéricos avanzados llevan este concepto más allá al introducir características adicionales como restricciones, valores predeterminados y múltiples tipos, que permiten a los desarrolladores escribir código más sólido y seguro en cuanto a tipos. En este artículo, se utilizarán ejemplos para explorar estos conceptos avanzados en genéricos.
Restricciones genéricas
Las restricciones limitan los tipos que un genérico puede aceptar. Esto garantiza que el tipo que se pasa a una función o clase genérica cumpla con ciertos criterios. Por ejemplo, se puede utilizar una restricción para garantizar que el tipo genérico tenga una propiedad o un método específicos.
function getLength<T extends { length: number }>(arg: T): number {
return arg.length;
}
const stringLength = getLength("TypeScript");
const arrayLength = getLength([1, 2, 3]);
En este ejemplo, la restricción <T extends { length: number }>
garantiza que el argumento pasado a getLength
tenga una propiedad length
.
Múltiples genéricos
TypeScript permite el uso de múltiples tipos genéricos en la misma función, clase o interfaz. Esto resulta útil cuando se trabaja con pares de valores u otras estructuras de datos que involucran múltiples tipos.
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const stringNumberPair = pair("TypeScript", 2024);
Esta función, pair
, acepta dos tipos genéricos diferentes, T
y U
, y devuelve una tupla que contiene ambos tipos.
Tipos genéricos predeterminados
Los genéricos en TypeScript también pueden tener tipos predeterminados. Esto resulta útil cuando se desea que un genérico tenga un tipo de respaldo si no se proporciona ningún tipo específico.
function identity<T = string>(value: T): T {
return value;
}
const defaultString = identity("Hello"); // T is string
const customNumber = identity<number>(100); // T is number
En este ejemplo, si no se pasa ningún tipo a identity
, el valor predeterminado es string
.
Uso de genéricos con interfaces
Los genéricos se pueden utilizar con interfaces para definir estructuras complejas en las que los tipos no son fijos. Esto añade flexibilidad a la forma en que se gestionan los datos.
interface Container<T> {
value: T;
}
const stringContainer: Container<string> = { value: "Hello" };
const numberContainer: Container<number> = { value: 42 };
La interfaz Container
está diseñada para contener un valor de cualquier tipo, lo que permite diferentes tipos de contenedores con tipos específicos.
Clases genéricas
Las clases en TypeScript también pueden ser genéricas. Esto resulta especialmente útil al diseñar clases que funcionan con distintos tipos de datos, como clases de almacenamiento o de recopilación de datos.
class DataStore<T> {
private data: T[] = [];
add(item: T): void {
this.data.push(item);
}
getAll(): T[] {
return this.data;
}
}
const stringStore = new DataStore<string>();
stringStore.add("Hello");
stringStore.add("TypeScript");
const numberStore = new DataStore<number>();
numberStore.add(42);
En este ejemplo, la clase DataStore
funciona con cualquier tipo de datos, proporcionando una forma segura de almacenar y recuperar elementos.
Conclusión
Los genéricos avanzados en TypeScript son una herramienta poderosa para escribir código flexible, reutilizable y con seguridad de tipos. Al usar restricciones, tipos múltiples, valores predeterminados y genéricos en clases e interfaces, los desarrolladores pueden escribir código más complejo y sólido. Comprender y utilizar estos conceptos avanzados permite una mayor flexibilidad y garantiza la seguridad de tipos en todas las aplicaciones.