1 Temporada 1
Aquí empieza la primera temporada de mi curso de TypeScript. Este vídeo ni siquiera es una introducción a TypeScript. Busco contarte cómo voy a orientar este curso y qué puedes esperar de él.
🇺🇦 Слава Україні! Consulta cómo puedes ayudar a Ucrania desde España u otros países en supportukrainenow.org.
TypeScript es un lenguaje de programación derivado de JavaScript que permite fabricar aplicaciones web y NodeJS aprovechando el código JavaScript que ya conoces, pero mejorándolo con un sistema de tipos que te hará perder menos tiempo depurando errores o peleándote con tu editor de código fuente para que lo puedas aprovechar en crear nuevas funciones y ser más eficiente con tu tiempo.
Aquí empieza la primera temporada de mi curso de TypeScript. Este vídeo ni siquiera es una introducción a TypeScript. Busco contarte cómo voy a orientar este curso y qué puedes esperar de él.
En este capítulo os presento TypeScript, os cuento qué es, cómo funciona, y por qué ha revolucionado la forma en la que miles de equipos de trabajo de todas partes del mundo han cambiado y mejorado la forma en la que programan.
En este capítulo ejecuto una terminal e instalo TypeScript en un proyecto de NodeJS (con su package.json). Os enseño alternativas para instalar TypeScript de manera local o global, y hacemos un par de pruebas para asegurarnos de que ha quedado bien instalado.
TypeScript se levanta por encima de JavaScript. Y la prueba de ello es este primer ejemplo de hola mundo de los que voy a programar en esta introducción, y es que voy a empezar a trabajar de momento sin tipos, escribiendo un pequeño hola mundo para mostrar cómo compilar código, que todavía no tiene tipos ni nada.
El ejemplo que hicimos en el capítulo anterior es muy básico porque no tiene tipos. En este capítulo vamos a hacer un hola mundo un poco más desarrollado y vamos a introducirle tipos para que podamos ver algo más parecido a lo que luego haremos en el mundo real cuando usemos TypeScript.
Empezamos con el módulo de tipos presentando tres tipos que hay en TypeScript que también vienen de JavaScript. Con el tipo Number podemos declarar números. Con el tipo Boolean podemos declarar valores lógicos. Con el tipo String podremos declarar cadenas de caracteres para valores más literarios.
TypeScript tiene una serie de tipos adicionales propios que no existen en JavaScript y que se usan para mejorar el funcionamiento del analizador de tipos. Con los tipos null y undefined podemos asegurarnos de que una variable pueda aceptar valores nulos o no definidos. Con el tipo void podremos tipar funciones que no generan salida. Y con any podremos excluir cualquier variable, argumento o función del sistema de tipados.
Los arrays son un tipo de valor compuesto que tiene JavaScript para asignar a una variable una colección de valores. Con TypeScript podemos tipar variables de tipo array, o vector, para que puedan tener asignados múltiples valores. Con las tuplas, además, podemos dotarle de cierta estructura a cada uno de los elementos de ese array.
Los objetos son uno de los tipos de datos más importantes de JavaScript. Permiten guardar arbitrariamente y de forma estructurada información. En TypeScript, si declaramos objetos, tenemos la posibilidad de tiparlos para que el compilador y el editor de textos sepa qué campos podemos utilizar.
Las funciones de TypeScript son como las funciones de JavaScript. En este capítulo escribo funciones en TypeScript y presento las ventajas de tipar adecuadamente sus entradas y sus salidas para prevenir errores cuando las invoquemos.
Todos los tipos que tenemos para tipar funciones, y haciendo ejemplos más complejos de funciones para demostrar la flexibilidad de su sistema de tipos. Por ejemplo, ¿quieres hacer una función arrow? Tipable. ¿necesitas que tu función acepte como parámetro una función de callback? Tipable.
Regreso a tu pantalla para presentar las clases y la orientación a objetos en TypeScript y JavaScript. Esto no es un curso que pretenda tratar orientación a objetos y patrones de diseño orientados a objetos, ni mucho menos, pero como no todo el mundo puede haber trabajado con clases en ECMAScript, he considerado conveniente hacer esta introducción para presentaros el funcionamiento de las clases en TypeScript.
Nos tiramos a saco a la creación de clases en TypeScript mostrando un ejemplo sencillo en el que declaramos algunas propiedades y algunos métodos. También se aprovecha para introducir el concepto de constructor.
Con el modificador private podemos ocultar algunos atributos pertenecientes a una clase para que desde fuera no puedan ser vistos y modificados, facilitando así que nuestras clases sólo expongan la información que están dispuestos a exponer.
Con el modificador readonly podemos hacer que un atributo pueda ser constante. Una vez se le declara un valor ya no puede ser modificado, ni dentro ni fuera de la clase.
Los getters y setters permiten fabricar atributos virtuales donde acceder al atributo ejecuta una función que devuelve el valor del atributo, y establecer el valor del atributo ejecuta otra que permitirá modificarlo.
La herencia es una propiedad importante que tiene la orientación a objetos que permite a las clases especializarse y fabricar jerarquías, sustituyendo sus comportamientos generales por otros específicos a medida que se baja en la jerarquía. En este capítulo hago un sistema de clases que usa herencia en TypeScript.
Cuando se usa orientación a objetos y herencia, el modificador protected limita el atributo al que se le aplique este modificador para que sólo esa clase y las clases descendientes puedan verlo. También hablo de abstract, que permite hacer clases abstractas, que no pueden ser instanciadas.
Con los alias de tipos (o type alias) tenemos la posibilidad de renombrar y darles nombres propios a otros tipos ya existentes, sean primitivos, objetos, colecciones...
Los tipos literales son un tipo especial que en vez de registrar un rango de valores pertenecientes a un tipo primitivo o complejo (como un string, un number o un objeto con tres clave-valores), representa un único valor primitivo, con el que le decimos a TypeScript que una variable sólo puede tener un único valor de todos los valores posibles del mundo.
Con las uniones de tipos, TypeScript nos permite crear tipos compuestos, para que su sistema de comprobaciones admita múltiples tipos de forma paralela; por ejemplo, para cuando quieres que una función pueda aceptar tanto un número como un entero.
Uno de los problemas de las uniones de tipos es que es dificil dentro del propio código fuente que emplea una variable de tipo unión distinguir cuando la variable es de uno de los tipos concretos de la composición. Por suerte, las uniones discriminantes son una función inteligente de TypeScript para poder distinguir fácilmente entre un tipo atómico concreto dentro de una unión de tipos.
Con las intersecciones de tipos podemos fabricar tipos nuevos que extienden el cuerpo de otros tipos, para hacer un tipo más grande que integra todos los campos declarados por los tipos que los componen. En este vídeo os los presento y os cuento algunos ejemplos.
Las interfaces son una de las particularidades más importantes de TypeScript (y también una de las más antiguas), mediante las cuales se pueden declarar tipos de una manera similar y a veces más flexible que mediante los tipos alias, con los que podemos definir la forma de los objetos que luego usaremos en nuestros programas.
Segundo vídeo dedicado a interfaces, donde presento los modificadores que podemos usar para alterar la manera en la que TypeScript tratará los campos de una interfaz, así como la forma de declarar funciones, que tendrán que estar disponibles en los objetos y clases que implementen las interfaces.
Como en otros lenguajes de programación orientados a objetos, las interfaces pueden utilizarse para fabricar un contrato o una especificación con operaciones que debe tener una clase. En este vídeo os enseño cómo implementar interfaces en clases y cómo usarlos para fabricar abstracciones.
Las interfaces pueden especializarse mediante un sistema de herencia similar al que utilizan las clases, de tal manera que podemos tener interfaces que heredan los campos y propiedades de otras interfaces superiores en la jerarquía.
Un tipo indizado es un tipo que permite acceder a elementos mediante índices, como por ejemplo, un array o un objeto. En este vídeo explico cómo utilizar las interfaces para anunciar que la interfaz admite acceso indizado.
Las interfaces también pueden ser usadas para declarar prototipos de funciones (por ejemplo, entradas y salidas de una función). Esto nos permite también declarar tipos híbridos, que es una función interesante que heredamos de JavaScript en la que una función puede tener campos adicionales cuando le ponemos un punto.
¿Por qué he dejado las interfaces para tan tarde cuando tantos cursos de TypeScript lo tratan casi lo primero? Pues porque ya no hay tantas diferencias entre un type alias y una interfaz. Aun así, en este vídeo os cuento diferencias entre un sistema y otro y os cuento cosas que no se pueden hacer con los type aliases.
Los casteos permiten engañar al sistema de tipos para que trate una variable de un tipo concreto como si fuese una variable de otro tipo. Los casteos tienen su riesgo, porque pueden provocar fallos en tiempo de ejecución, pero son beneficiosos en determinadas situaciones, por ejemplo, para forzar al sistema de tipos a ver una abstracción como si fuese un objeto de un tipo concreto.
instanceof es una palabra clave de JavaScript que hereda TypeScript que permite comprobar si un objeto es de una clase concreta. Para comprobaciones más complejas que permitan distinguir si una variable es de un tipo u otro, TypeScript tiene las guardas.
Los tipos enumerados son una interesante alternativa que tiene TypeScript para declarar una serie de valores relacionados entre sí, que podemos usar para tipar variables donde queramos que el dominio de valores que se pueden aceptar quede limitado a un subconjunto pequeño.
En este vídeo descubrirás que un tipo enumerado realmente no es más que una manera de darle un nombre descriptivo a una constante, sea numérica o alfanumérica, de tal manera que para el ordenador una variable siga teniendo un valor concreto que pueda usar en APIs si hace falta, pero para nosotros tenga un nombre más claro y descriptivo.
No todos los lenguajes de programación tienen soporte para enumerados en los que el valor asignado a algunos o todos los miembros de la enumeración se compute dinámicamente en tiempo de ejecución, pero TypeScript sí. En este vídeo os cuento como aprovechar esta función, aunque no es una función que deberías usar demasiado.
Los genéricos permiten parametrizar las declaraciones de tipos e interfaces, de tal manera que algunos de los campos no especifiquen el tipo de datos que emplean hasta el momento en el que preparamos la variable o parámetro en el que vamos a necesitar ese tipo. Esto nos permite fabricar interfaces reusables y reducir la cantidad de código que necesitamos en nuestros programas.
Mucha gente tiene problemas para entender o utilizar los genéricos porque comete el error de darle a su genérico nombres compuestos por una única letra, como K, V o T. Esto es un error, y en este vídeo, trato de explicarte que en TypeScript un genérico puede ser un identificador con todas las letras que necesites, algo que hará tu código más sencillo de mantener.
Las funciones también pueden especificar genéricos, de tal manera que el tipo de datos de uno de los parámetros de la función es desconocido hasta el momento en el que se invoca la función y se especifica el valor de ese parámetro. Esto tendrá una serie de consecuencias interesantes en la forma en la que accedemos a esa variable.
Para facilitar el uso de una variable cuyo tipo usa genéricos en una función, lo normal es que pongamos restricciones, de tal manera que los genéricos que empleamos en tipos y funciones formen parte de una jerarquía de tipos que le asocie cierto contexto para hacerlos más fáciles de usar.
Los tipos de utilidad son una serie de tipos basados en genéricos que integra TypeScript de forma nativa en el propio núcleo del lenguaje, que permiten expresar álgebras de tipos más complejos. Para ver la lista completa de tipos de utilidad, consulta https://www.typescriptlang.org/docs/handbook/utility-types.html.
Para Node, un módulo es un archivo de código fuente independiente entre sí. Con la palabra clave export, podemos explicarle a Node que un elemento de uno de los archivos, como una función, una clase, o la declaración de un tipo o una interfaz, debería estar disponibles para otros módulos que quieran importarlo y así reutilizar código.
Una vez que vimos el funcionamiento de export, TypeScript también soporta la palabra clave import, procedente de ECMAScript 2015, con la que podemos importar desde otros módulos elementos que hayamos exportado previamente usando export, para poder referenciar las funciones, constantes y tipos declarados en esos archivos.
Relacionado con el sistema ES Modules, vamos a ver cómo usar dos tipos especiales de import y export. Con export default podemos exportar de manera predominante algún elemento en un módulo, para importarlo sin necesidad de corchetes. Con import asterisco podemos importar de golpe todos los elementos exportados por un módulo.
Para proyectos de tamaño considerable, tsconfig.json es un archivo que se usa para configurar con mejor precisión un proyecto de TypeScript. En este capítulo explico cómo crear uno de estos archivos para ajustar de forma precisa la forma en la que se compila el proyecto.
Retomamos lo de los módulos para explicar las consecuencias de usar TypeScript a la hora de descargar módulos desde NPM.
Cuando el código fuente descargado desde NPM se niegue a funcionar bien en TypeScript, deberemos prestar atención por si necesitásemos importar manualmente un archivo de definición de tipos para integrar el proyecto. El espacio de nombres @types genera definiciones de tipos si es posible para facilitar esta integración. Con esto cerramos esta temporada.
Empezamos un caso de uso práctico en el que voy a mostrar cómo es la creación de una pequeña API REST con Express que pueda responder a consultas rápidas hechas a su endpoint. En este primer capítulo, creo un proyecto configurándolo correctamente: su package.json, su tsconfig.json, instalamos TypeScript, rimraf, montamos scripts... y le damos salida.
En este vídeo configuramos una aplicación Express que quede a la escucha en un puerto, para que cuando se haga una petición HTTP se ejecute la función que vamos a usar para manejar y devolver una respuesta.
Con los JSONs que importamos en nuestra aplicación en el primer capítulo, vamos a hacer un par de funciones que nos permitan recuperar información de los catálogos, que será la que luego sirvamos en la aplicación.
Pues ahora queda cerrar este mini-caso de ejemplo conectando todas las piezas y haciendo que visitar el endpoint que hemos declarado en Express ejecute las funciones y nos devuelva contenido útil desde el endpoint.