Bienvenidos sean a este post, hoy comentaremos mas sobre los archivos de declaracion.
El archivo de declaracion es un tipo especial de archivo usado por el compilador de typescript. Se usa unicamente en la compilacion y es un archivo de referencia para describir en javascript, si lo debemos comparar con otros archivos es similar a los archivos de encabezado de C/C++ (.h). Esto es asi porque unicamente describen la estructura de metodos y propiedades disponibles pero no su implementacion.
Si bien hoy tenemos muchos servidores web que utilizan un engine para generar las paginas html como pueden ser:
- ASP.NET mvc
- Node.js
En ambos casos nos permiten renderizar las paginas mediante engines del lado del servidor y en algunas ocasiones se incluye codigo javascript dentro del html renderizado como parte de su logica. Para este ejemplo vamos a suponer que debemos mantener una lista de contactos de email a la cual accederemos mediante una variable global, primero generemos un archivo con el siguiente codigo:
index.html
<body>
<script type="text/javascript">
var CONTACT_EMAIL_ARRAY = [
"ayuda@tinchicus.com",
"contacto@tinchicus.com",
"webmaster@tinchicus.com"
]
</script>
</body>
Esta es una pagina simple de html donde tenemos el body e implementado una tag de script que contiene un array con tres direcciones de e-mail. Ahora pasemos a typescript donde crearemos un nuevo archivo y agregaremos el siguiente codigo:
declarar.ts
class logGlobal {
public static globalAconsola() {
for(let email of CONTACT_EMAIL_ARRAY) {
console.log('contacto: ' + email);
}
}
}
window.onload = () => {
logGlobal.globalAconsola();
}
Aqui tenemos una clase con una funcion estatica que tomara los valores del array global que establecimos anteriormente y los mostrara en la consola del log. Lo siguiente es crear una funcion que llamara a este metodo estatico cuando se cargue la ventana. Si lo compilan nos devolvera el siguiente error:
error TS2304: Cannot find name 'CONTACT_EMAIL_ARRAY'.
Esto nos indica que el codigo anterior desconoce completamente la existencia de tal variable porque esta disponible solo cuando el servidor este corriendo. Aqui entra en accion el archivo de declaracion, nuestro siguiente paso sera crear un archivo con el nombre de globals.d.ts y le agregaremos el siguiente codigo:
globals.d.ts
declare const CONTACT_EMAIL_ARRAY: string[];
En este caso no solamente le damos visualizacion a nuestro codigo de typescript sino que mediante la palabra declare le estamos diciendo que esto sera definido en algun momento de la ejecucion. Si lo compilan notaran que no devolvera ningun error y ya tenemos nuestro codigo de javascript para implementar en el html. Nuestro siguiente paso sera implementar estos cambios y para ello debemos ir de nuevo al archivo index.html y agregaremos el siguiente codigo al inicio del archivo:
<head>
<script src="declarar.js"></script>
</head>
<title>Pagina de prueba</title>
<body>
<script type="text/javascript">
var CONTACT_EMAIL_ARRAY = [
"ayuda@tinchicus.com",
"contacto@tinchicus.com",
"webmaster@tinchicus.com"
]
</script>
</body>
Este nos habilitara el codigo javascript que generamos, este es el nombre del archivo que le asigne pero ahi deben poner el nombre del que generaron ustedes, asi como tambien un titulo para identificar a la pagina cuando este cargada y con esto ya deberia funcionar este proyecto pero como podemos probarlo? Bueno, aqui ejecutaremos el siguiente comando:
$ npm install -g http-server
Este nos instalara un servidor http ligero para poder realizar nuestras pruebas, una vez instalado simplemente en el directorio donde esta index.html ejecutaremos lo siguiente:
$ http-server
Esto iniciara nuestro servidor y nos dara un mensaje como el siguiente:
$ http-server
Starting up http-server, serving ./
http-server version: 14.1.1
http-server settings:
CORS: disabled
Cache: 3600 seconds
Connection Timeout: 120 seconds
Directory Listings: visible
AutoIndex: visible
Serve GZIP Files: false
Serve Brotli Files: false
Default File Extension: none
Available on:
http://127.0.0.1:8080
http://172.128.11.3:8080
Hit CTRL-C to stop the server
Observen que ya esta disponible y solamente deben ir a algunas de la direccion informada mediante un navegador y deberian tener algo como esto

Es solo una pagina en blanco pero la magia va a ocurrir en el interior, para ello deben ir a la opcion de inspeccionar, por lo general es simplemente hacer click con el boton derecho en la pagina y les abrira la parte de depuracion. En esta deben seleccionar la opcion de consola y deberian tener lo siguiente:

Como pueden ver en la consola del navegador nos aparecio los tres datos del array por lo tanto podemos decir que se llamo correctamente a nuestra funcion estatica. La primera curiosidad es que pudimos utilizar la variable mediante nuestro script sin tenerla. Esto es gracias al archivo de declaracion donde la tenemos declarado pero la definimos mediante el evento onload cuando llamamos a la funcion estatica.
Ya vimos como trabaja un archivo de declaracion pero como sabemos cual es la correcta para nuestras librerias de terceros? afortunadamente al poco de salir de typescript, Boris Yankov creo un GitHub para almacenar archivos de declaracion de terceros y con el tiempo se transformo en el repositorio a ir para estos temas. El siguiente tema fue como buscarlas y obtenerlas, y si bien hoy tenemos varias herramientas disponibles; la forma mas practica es mediante npm install tal como vimos en este post. Pero vamos a repasar como era, primero debemos instalar el modulo, tomemos este caso como ejemplo:
$ npm install underscore
Este comando instalara el modulo underscore y para instalar los archivos de declaracion debemos ejecutar el siguiente comando:
$ npm install @types/underscore --save-dev
Este sera el encargado de instalar los archivos de declaracion, siempre iran con el @types/ antes del nombre para indicar que debe descargar ese tipo de archivos, el parametro es para establecerlo que sea parte de la seccion de desarrollo y no produccion. Pero que sucede si no instalamos el archivo de declaracion? les devolvera un mensaje como el siguiente:
Could not find a declaration file for module 'underscore'
Try `npm i --save-dev @types/underscore` if it exists
or add a new declaration (.d.ts) file containing `declare module 'underscore';
Nos indicara que ejecutemos el comando o bien generemos un archivo con la linea entre las comillas, tal como hicimos en el ejemplo anterior pero esta vez con module y el nombre. Antes existia una pagina para buscar este tipo de archivos pero desde que npm y yam nos entregan mucha informacion sobre los mismos ya no es necesaria.
Vamos a analizar un siguiente donde intentaremos integrar un modulo de javascript existente en un proyecto de typescript. Analicemos primero el codigo de javascript:
var ErrorHelper = (function () {
return {
containsErrors: function (response) {
if (!response || !response.responseText) {
return false;
}
var errorValue = response.responseText;
if (String(errorValue.failure) === "true"
|| Boolean(errorValue.failure)) {
return true;
}
return false;
},
trace: function (msg) {
var traceMessage = msg;
if (msg.responseText) {
traceMessage = msg.responseText.errorMessage;
}
console.log("[" + new Date().toLocaleTimeString()
+ "] " + traceMessage);
}
}
})();
var failureMessage = {
responseText: {
"failure": true,
"errorMessage": "Mensaje desde failureMessage"
}
};
var failureMessageString = {
responseText: {
"failure": "true",
"errorMessage": "Mensaje desde failureMessageString"
}
};
var successMessage = {
responseText: {
"failure": false
}
};
if (ErrorHelper.containsErrors(failureMessage))
ErrorHelper.trace(failureMessage);
if (ErrorHelper.containsErrors(failureMessageString))
ErrorHelper.trace(failureMessageString);
if (!ErrorHelper.containsErrors(successMessage))
ErrorHelper.trace("Exitos!");
Este codigo sera para indicarnos si existen errores y un detalle sobre los mismos. Lo primero sera una variable que contendra dos metodos, el primero es para indicar si existe un error y el segundo para pasar el mensaje de descripcion como un log. En el primer caso tenemos una funcion que recibe un valor y en este evaluaremos si no se recibio ningun valor o de descripcion procedemos a devolver un false. El siguiente condicional verifica si es de tipo string e igual a true o de tipo boolean pero tambien true devolvera un true, en caso contrario es ignorado y devuelve de manera predeterminada un false. Como dijimos este es el encargado de indicar si hubo un error o no. El segundo caso es otra funcion que recibe un valor, lo primero es definir una variable que almacena el valor recibido. Despues tenemos un condicional que verifica si existe una propiedad en el valor recibido, en caso de ser afirmativo almacenaremos en la variable la propiedad encargada de contener la descripcion del error. Para finalmente mostrar la fecha del momento seguido del mismo.
Esta variable tiene una particularidad porque si eliminamos todo el codigo interno nos quedaria de la siguiente manera:
var ErrorHelper = (function () { ... })();
Esto es denominado como IIFE (Expresion de Funcion Invocado Inmediatamente, por sus siglas en ingles), donde mediante los parentesis finales la funcion que esta dentro se ejecutara inmediatamente. Es decir, todo lo que este dentro de esa estructura se ejecutara inmediatamente al ser invocado. Continuemos con el codigo, despues tendremos tres variables. En las primeras dos pasamos errores primero con un valor booleano y el otro string para indicar la falla y un mensaje descriptivo, en el tercer caso es para cuando no ocurre una falla. Por ultimo tenemos tres llamados a containsErrors donde pasaremos los valores anteriores y luego usaremos a trace para ver los mensajes de cada una de las variables, salvo el ultimo caso donde pasamos un literal. Si lo prueban su salida sera como esta:
[12:36:17] Mensaje desde failureMessage
[12:36:18] Mensaje desde failureMessageString
[12:36:18] Exitos!
Ahora que tenemos el codigo debemos crear nuestro archivo de declaracion para poder implementarlo correctamente. Recuerdan cuando vimos que al intentar usar una libreria sin el archivo de declaracion nos informaba que en caso de no existir debiamos crear un archivo y usar a module para implementarlo. Aqui debemos hacer lo mismo, podemos usar el archivo globals.d.ts y agregar el siguiente codigo:
declare module ErrorHelper {
function containsErrors(response: any): boolean;
function trace(message: any): void;
}
Usaremos a declare module seguido del nombre de la IIFE y en esta declaramos los dos metodos pero con el tipo any para poder recibir cualquier tipo de dato pero esto se puede mejorar:
interface IResponse {
responseText: IFailureMessage;
}
interface IFailureMessage {
failure: boolean | string;
errorMessage?: string;
}
declare module ErrorHelper {
function containsErrors(response: IResponse): boolean;
function trace(message: IResponse | string): void;
}
En este caso creamos dos interfaces, el primero sera para usarlo en containsErrors y el segundo es para el tipo que usaremos en la primer interfaz. En esta segunda interfaz la usaremos para representar los valores que pasamos donde el indicador de falla puede recibir solo esos tipos de valores y el de mensaje es opcional y solo de tipo string. Luego reemplazamos el any con la primera interfaz y en la segunda declaracion damos la opcion de string y por ultimo indicamos que tipo de dato devolveran. Con esto ya podemos incorporarlo en cualquier codigo de typescript porque al momento de compilarlo ya lo tendremos declarado.
En resumen, hoy hemos visto archivos de declaracion, que es, para que sirve, como se utiliza, las distintas opciones que disponemos, asi como tambien algunos temas propios de este tema. 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
