0

TypeScript | Javascript – 2nd Edition #5

En esta quinta entrega tocaremos el tema de funciones y genéricos. Como se usan en TypeScript y que nos brinda para trabajar con ellos. Nuevamente utilizaremos VS Code en algunos ejemplos.

Funciones

Tenemos 2 formas de declarar funciones. Una es de forma anónima la otra es por medio de un nombre. Esto es igual que en javascript no tenemos diferencias:

// por Nombre
function GetSum(x, y) {
	return x + y;
}

// funcion anonima
let sum = function(x, y) { return x+y; };

Ahora veamos el enfoque con los tipos de TypesCript como debería ser declarada la misma función para tener la validación de tipos.

// por Nombre
function GetSum(x: number, y:number): number {
	return x + y;
}

// funcion anonima
let sum = function(x: number, y: number): number { return x+y; };

En el ejemplo declaramos que parámetros recibiremos en la función. Van a ser de tipo numérico y que a su vez esta función nos devolverá también un tipo de dato numérico. 

Inferencias de tipos

Un tema interesante es la inferencia de tipos. Lo que hace el compilador es detectar que tipo valor le estamos agregando, por ejemplo:

let x = 1;

let x: number = 1;

Al asignar un valor numérico automáticamente sabe de qué tipo es  y no es necesario usar la forma larga como vemos en la segunda línea.

Vamos a ver un ejemplo de una matriz. En una matriz el compilador decidirá cuál es el mejor tipo:

let x = [”Fernando”, “Pepe”, null];

¿Y qué pasa con las clases? veamos el ejemplo:

class herramienta{}

class Martillo extends herramienta{}

class Destornillador extends herramienta{}

class Lijadora extends herramienta{}

let list = [ new Martillo(), new Destornillador(), new Lijadora() ]

El compilador tomará como tipo el primero de la lista del array. En estos casos debemos declararle de que tipo.

let list: Herramienta[] = [ new Martillo(), new Destornillador(), new Lijadora() ]

Tipos Genéricos

El objetivo de los tipos genéricos es generar clases altamente reutilizables. Podemos crear piezas de software que pueden accionar sobre un gran cantidad de tipos comunes. Esto permite que cualquier persona que lo utilice junto a sus tipos personales. Hoy la gran mayoría de los lenguajes de programación lo soportan y TypeScript no podía quedarse afuera.

Para empezar veamos un ejemplo que:

function GetValue(arg: number): number {
    return arg;
}

Supongamos que en lugar de usar number usamos any, sería un forma de hacerla genérica, pero en verdad no es conveniente, estaríamos perdiendo información útil del tipo y su funcionalidades. Ahora bien, cómo debemos declararlo de forma genérica:

function GetValue<T>(arg: T): T{
    return arg;
}

En el ejemplo vemos que agregamos la variable T que a diferencia de any sera mas precisa sin perder ninguna información del tipo. Ahora que tenemos nuestra declaración vemos como debemos invocar.

let result = GetValue<string>("hola mundo");

<string> le dice que el parámetro que vamos a pasar es de ese tipo. También podemos llamara de la forma más simple y el compilador infiere el tipo automáticamente siendo tal vez un poco más legible.

let result = GetValue("hola mundo");

Ahora bien, que problema vemos en el siguiente ejemplo:

function GetValue<T>(arg: T): T
{
    return arg.length;
}

Si pasamos el tipo string no habrá ningún problema pero si pasamos del tipo numeric no posee la propiedad length y nos dara un error. 

En cambio, por ejemplo, si trabajamos con matrices esta funcionalidad, length estará presente en todos los tipos.

function GetValue<T>(arg: T[]): T[]{
    return arg.length;
}

// Otra forma de declarar

function GetValue<T>(arg: Array<T>): Array<T>{
    return arg.length;
}

Ahora vemos como hacer un clase genérica:

class GenericClass<T>{
    add(arg1: T, arg2: T) => T
}

let myGenericClass = new GenericClass<numeric>();
myGenericClass.add = function(arg1, arg2) {
   
     return arg1 + arg2;
}

Por último, vamos hacer limitaciones en los tipos genéricos. Como vimos en el ejemplo al hacer una clase genérica puede ser que el tipo que pasamos no tenga un funcionalidad como en el caso que devolvía length. 

Lo que podemos hacer es restringir una función para trabajar con todos los tipos tengan o no la propiedad length.

Para esto necesitamos crear una interface:

interface WithLength {
	length: number;
}

function GetValue<T extends WithLength>(arg: T): T {
	console.log(arg.length); 
	return arg;
}

Como podemos ver en la imagen ya no tendremos el problema ya que no tira errores.

Conclusión

Hemos explorado el uso de funciones, la inferencia de tipos y hemos tenido una primera aproximación a los tipos genéricos. Aunque es solo el comienzo, constituye un sólido punto de partida para adentrarnos aún más en el tema. En nuestro próximo artículo, abordaremos los conceptos de namespaces, módulos y decoradores, concluyendo así este tutorial introductorio para principiantes.

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *