Genéricos en TypeScript
Este artículo explica los genéricos en TypeScript.
YouTube Video
Genéricos en TypeScript
Los genéricos en TypeScript son una característica que permite definir funciones, clases e interfaces reutilizables y seguras en cuanto a tipos mediante la parametrización de tipos. Usar genéricos te permite escribir código que no depende de tipos específicos, lo que permite realizar las mismas operaciones en varios tipos.
Fundamentos de los Genéricos
Los genéricos actúan como plantillas que aceptan tipos como argumentos, permitiendo que las funciones y clases gestionen diferentes tipos.
Funciones Genéricas
El siguiente es un ejemplo de una función con sus tipos de argumentos especificados usando genéricos.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity<number>(42)); // 42
6console.log(identity<string>("Hello")); // Hello
T
es un argumento de tipo genérico que representa los tipos de los argumentos y el valor de retorno de la función. El tipo real se determina cuando se llama a la función.- Al especificar explícitamente
<number>
o<string>
, estás definiendo el tipo.
Los tipos genéricos funcionan sin una especificación explícita porque TypeScript realiza inferencia de tipos.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity(42)); // 42
6console.log(identity("Hello")); // Hello
Restricciones en los Genéricos
Al aplicar restricciones a los genéricos, puedes limitar que acepten solo tipos específicos.
1function loggingIdentity<T extends { length: number }>(arg: T): T {
2 console.log(arg.length);
3 return arg;
4}
5
6loggingIdentity("Hello"); // 5
7loggingIdentity([1, 2, 3]); // 3
8
9// loggingIdentity(42); // Error: number does not have a length property.
- Especificar
T extends { length: number }
indica queT
debe ser un tipo con una propiedadlength
. Por lo tanto, los tipos sin una propiedadlength
no serán aceptados.
Clases Genéricas
Las clases también pueden definirse usando genéricos. Las clases genéricas ofrecen tipos flexibles para propiedades y métodos.
1class Box<T> {
2 private _value: T;
3
4 constructor(value: T) {
5 this._value = value;
6 }
7
8 public getValue(): T {
9 return this._value;
10 }
11
12 public setValue(value: T): void {
13 this._value = value;
14 }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue()); // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue()); // Hello
Box<T>
declara el tipoT
utilizado dentro de la clase como un genérico. Esto permite reutilizar la misma clase para diferentes tipos.
Interfaces Genéricas
Los genéricos también se pueden usar con interfaces.
1interface Pair<T, U> {
2 first: T;
3 second: U;
4}
5
6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
7console.log(numberStringPair); // { first: 1, second: 'One' }
8
9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair); // { first: true, second: [ 1, 2, 3 ] }
- Al especificar dos tipos genéricos con
Pair<T, U>
, puedes definir un objeto con una combinación de tipos diferentes.
Argumentos de Tipo Predeterminados
También es posible especificar un tipo predeterminado para los argumentos de tipo genéricos.
1function createArray<T = string>(length: number, value: T): T[] {
2 return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a")); // ['a', 'a', 'a']
6console.log(createArray(3, 100)); // [100, 100, 100]
- Estamos configurando el argumento de tipo predeterminado como
string
con<T = string>
. Si no se especifica un tipo explícitamente,T
será del tipostring
.
Alias de Tipos Genéricos
Los genéricos también se pueden usar como alias de tipo (type
).
1type Result<T> = {
2 success: boolean;
3 data: T;
4};
5
6const successResult: Result<number> = { success: true, data: 42 };
7const errorResult: Result<string> = { success: false, data: "Error occurred" };
8
9console.log(successResult); // { success: true, data: 42 }
10console.log(errorResult); // { success: false, data: 'Error occurred' }
Result<T>
representa un objeto de resultado que contiene datos del tipoT
. De esta manera, puedes crear alias de tipo flexibles utilizando genéricos.
Múltiples Tipos Genéricos
Al usar múltiples tipos genéricos, puedes definir funciones y clases aún más versátiles.
1function merge<T, U>(obj1: T, obj2: U): T & U {
2 return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged); // { name: 'Alice', title: 'Engineer' }
- La función
merge
toma dos tipos diferentesT
yU
y los combina para devolver un nuevo objeto.
Resumen
- Los genéricos permiten escribir código reutilizable y seguro al tratar los tipos como parámetros.
- Al utilizar genéricos en funciones, clases e interfaces, puedes escribir una lógica flexible que maneje varios tipos.
- Al añadir restricciones a los argumentos de tipo o configurar argumentos de tipo predeterminados, puedes controlar el alcance de los genéricos.
Al usar genéricos, puedes escribir código independiente del tipo y de propósito general, aprovechando al máximo el poderoso sistema de tipos de TypeScript.
Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.