Bienvenidos sean a este post, hoy veremos varios tipos de implementaciones en nuestros archivos.
En el post anterior vimos como mediante las palabras declare y module podemos definir objetos y namespaces. Tambien vimos que se puede utilizar a interface para generar tipos personalizados como vimos con typescript, inclusive usan la misma sintaxis, y gracias a esto podemos utilizar varias tecnicas para poder realizar sobrecarga, union de tipos, clases y otros mas. A continuacion veremos cada uno de ellos.
Sobrecarga de funciones
En los archivos de declaracion podemos realizar las sobrecargas de las funciones tal como hacemos en un codigo normal de typescript, les paso un ejemplo:
declare function mostrar(arg: string | number | boolean);
declare function mostrar(arg: { id: number; nombre: string });
Esta es la sobrecarga de una funcion llamada mostrar para que la primera solo reciba un argumento de tres tipos distintos. Pero recuerden que estas son solo declaraciones, en el codigo deben definirlas, pero ya el compilador las tendra disponible sabiendo que se declararan en algun punto.
Namespaces anidados
Los archivos de declaracion nos permiten anidar distintos nombres de modulos, o lo mismo que decir se pueden anidar namespaces, veamos un ejemplo simple::
declare module EspacioNombre1 {
module EspacioNombre2 {
module EspacioNombre3 {
function log(msg: string);
}
}
}
En este caso declaramos un modulo llamado EspacioNombre1, el cual expone al modulo EspacioNombre2 y este a su vez expone otro llamado EspacioNombre3. Dentro de este tendremos un metodo llamado log y ahora para poder llamarlo necesitamos pasar por los tres namespace, veamos como es el llamado:
EspacioNombre1.EspacioNombre2.EspacioNombre3.log("prueba");
Tal y como sucede con cualquier otro llamado a una funcion que se encuentra en un namespace.
Clases
Las clases se declaran como los modulos siempre primero con el declare pero seguido con la palabra class, como en cualquier codigo de typescript, y lo podemos declarar de la siguiente manera:
declare class clase {
public mostrar(): void;
}
Este es solo una declaracion de una clase y un metodo publico llamado mostrar pero no quita que podamos hacer lo siguiente:
let obj = new clase();
obj.mostrar();
Si bien esto no nos devolvera ningun error al momento de compilarlo tampoco hara nada hasta que definimos a la clase y al metodo porque trabaja de la misma forma que las interfaces.
Propiedades y metodos estaticos
Al igual que sucede con los codigos de typescript podemos marcar a nuestros elementos como static:
declare class clase {
static id: number;
static mostrar(): void;
}
Tenemos una clase donde el metodo y la propiedad fueron declarados como estaticos. Esto nos permitira usarlo de la siguiente manera:
clase.id = 10;
clase.mostrar();
Al igual que sucede con los elementos estaticos en un codigo normal para acceder usaremos directamente la clase y no una instancia. En el caso de la propiedad al asignarle un valor ya la estamos definiendo pero en el caso del metodo si debemos definirlo para poder utilizarlo.
Clases abstractas
Otra posibilidad que disponemos es la posibilidad de declarar clases y metodos como abstractas:
declare abstract class clase {
abstract mostrar(): void;
}
En este caso declaramos una clase y su metodo como abstractas. Veamos como puede ser su implementacion:
class claseHija extends clase {
mostrar() {}
}
En este caso definimos una clase que sera heredera de la clase abstracta con lo cual ya estaria implementado pero para poder usar al metodo debemos definirlo como se muestra en el ejemplo.
Genericos
Otro tipo que podemos declarar son los tipos genericos. Un ejemplo puede ser el siguiente:
declare function orden<T extends number | string>
(input: Array<T>): Array<T> { }
Esta funcion se encargara de ordenar dos tipos de valores como son number y string. Por esta razon se los asignamos al generico. El ingreso sera un array del tipo generico y la devolucion sera de la misma forma pero en lugar de terminarlo con el punto y coma le pasamos un bloque vacio. Si deseamos implementarlo en nuestro codigo podemos hacerlo de la siguiente manera:
let sortedStringArray: Array<string> = orden(["martin", "enzo", "ariel"]);
let sortedNumericArray: Array<number> = orden([6, 1, 4]);
Observen como se implemento,, suponiendo que ya definimos a la funcion orden, donde definimos la variable y le pasamos el tipo que sera para luego asignarle el resultado de llamar a la funcion. En ambos casos le pasamos el tipo valido de los arrays que acepta la declaracion en el archivo.
Tipos condicionales
Como indica el titulo tambien podemos declarar tipos condicionales y condicionales distribuidos, como se ve en el siguiente ejemplo:
declare type numeroOcadenaObooleano<T> =
T extends string ? string :
T extends number ? number :
T extends boolean ? boolean : never;
En este caso igual que al momento de hablar sobre los tipos condicionales en genericos para cada caso implementamos el operador condicional donde si el tipo coincide lo devolvemos. Pero en caso de ser contrario implementamos otro condicional hasta el ultimo caso donde el «else» devolvera un never. Es decir, que el tipo ingresado no es valido con ninguno de los anteriores. Vamos a analizar el siguiente caso:
type miNunca = stringOrNumberOrBoolean<[string,number]>;
En este caso definimos un alias de la declaracion anterior y le pasamos un tuple donde contiene a string y number, que suponen que sucedera en este caso? A pesar de pasar dos tipos validos del condicional el tipo devuelto siempre sera never porque el tuple no esta contemplado en las condiciones de los distintos operadores.
Inferencia de tipo condicional
Recien vimos que nos permite el tipo condicional, por ende tambien nos permite la inferencia de este tipo de datos. Analicemos el siguiente ejemplo:
declare type inferencia<T> =
T extends { id: infer U } ? U : never;
En este caso simplemente declaramos el tipo donde al igual que vimos en este post mediante la variable id e infer recibiremos un tipo para luego mediante el operador condicional lo pasaremos, en caso contrario pasaremos un never. El ultimo caso puede pasar un never debido a que lo pasamos en blanco o es de un tipo no valido. En todo caso si devolvemos un tipo este sera extendido por el generico y por lo tanto nuestro generico al ser heredero de este tipo podremos usarlo sin inconvenientes. Analicemos la siguiente implementacion:
type cadena = inferencia<{ id: string }>;
type nummero = inferencia<{ id: number }>;
Por ejemplo en el primer caso al recibir un tipo string por lo tanto este tipo solo manejara de este tipo, en el segundo caso ocurre lo mismo pero para number.
La idea de estos tipos y los archivos de declaracion es indicarle al compilador como sera la estructura previa del codigo de la libreria de javascript. Por esta razon se nos permite la utilizacion de palabras claves de typescript en nuestros archivos de declaracion y al igual que mencionamos en el post anterior este no deja de ser un archivo de encabezado de C/C++.
En resumen, hoy hemos vistos distintos tipos de datos y/o formas que podemos usar en los archivos de declaracion de typescript, asi como tambien algunos ejemplos genericos de cada una de las distintas declaraciones. Espero les haya resultado de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
