Introducción

Un poco de historia

Todo comenzó en octubre de 2012, cuando se hizo pública oficialmente la versión 0.8 del lenguaje TypeScript después de dos años de desarrollo interno en Microsoft. El equipo de desarrollo estaba dirigido por Luke Hoban y Anders Hejlsberg. Este último es conocido por haber participado en el origen de Turbo Pascal, así como de su sucesor, Delphi. Tras incorporarse a Microsoft en 1996, se hizo cargo del diseño de .NET Framework y del lenguaje C#. Hoy es el principal arquitecto del lenguaje TypeScript.

Cuando se lanzó, el lenguaje no fue un éxito rotundo. De hecho, la popularidad del lenguaje JavaScript estaba en auge y su ecosistema de herramientas crecía exponencialmente. Después del lanzamiento de Node.js en 2009, surgieron muchos frameworks frontend (del lado del cliente) (Backbone en 2010, Ember en 2011, AngularJS en 2012...).

images/01RI01.png

A partir de entonces, buena parte del desarrollo de las aplicaciones web se traslada al lado del cliente en el navegador y están surgiendo muchas herramientas para facilitar su escalabilidad y mantenibilidad. Estas herramientas satisfacen necesidades específicas:

  • Ejecución de pruebas (Karma, Mocha, Jest…)

  • Lanzamiento de tareas (Grunt, Gulp...)

  • Gestión de dependencias (NPM, Bower, Jspm...)

  • Empaquetador de aplicaciones (Browserify, Webpack, Rollup...)

Es difícil encontrar un lugar entre todas estas nuevas herramientas, de modo que TypeScript queda relegado a un segundo plano.

La versión 1.0 se lanzó en abril de 2014 y anunció un punto de inflexión: se podrían aceptar contribuciones de la comunidad. Para facilitar este cambio, el proyecto migró de CodePlex (la antigua plataforma de alojamiento de proyectos de código abierto de Microsoft) a GitHub en julio de 2014.

Adquirida por Microsoft en junio de 2018, GitHub es, desde hace varios años, la plataforma más utilizada para gestionar el código de proyectos de código abierto.

Desafortunadamente, eso no bastará para que TypeScript tenga éxito. El lenguaje aún adolece de falta de madurez y todavía no está completamente integrado en el ecosistema de herramientas de JavaScript. Por tanto, su uso se considera difícil y poco intuitivo, en particular por:

  • El compilador, que no es lo suficientemente eficiente y no tiene compilación de código fuente incremental. Esto se vuelve problemático cuando se desarrollan aplicaciones web con mucho código fuente (la compilación incremental solo se aplica a archivos que han sido modificados y, por lo tanto, optimiza el tiempo de ejecución de un compilador).

  • Integración en el IDE (Integrated Development Environment o entorno de desarrollo integrado en español), por entonces limitado y que ofrece muy pocas características interesantes. En ese momento, una de las pocas integraciones efectivas de TypeScript era con Visual Studio. Sin embargo, solo permitía el uso de la versión de TypeScript integrada en el IDE de Microsoft. Las actualizaciones de la versión del lenguaje eran demasiado restrictivas porque estaban vinculadas a la versión de Visual Studio, por lo que fue necesario aplicar actualizaciones de Visual Studio para obtener una versión más nueva de TypeScript. La única alternativa era Atom (un editor de texto creado por GitHub). Más ligero que Visual Studio, tenía ciertas funciones avanzadas a través de un complemento desarrollado por la comunidad (autocompletado, importación de módulos, devolución de errores de TypeScript...). 

  • La integración de bibliotecas JavaScript, demasiado difícil y poco intuitiva. TypeScript necesita archivos específicos que permitan tipar el código JavaScript procedente de bibliotecas (consulte la sección ¿Por qué TypeScript? - Tipado estático). La gran mayoría de estos archivos están escritos por la comunidad y, en 2014, la comunidad aún no era lo suficientemente grande como para cubrir todas las bibliotecas de JavaScript disponibles.

  • La falta de documentación para explicar cómo integrar el lenguaje...

ECMAScript

TypeScript es un superconjunto de JavaScript:

images/01RI03.png

Esta oración es importante porque significa que una línea de JavaScript es equivalente a una línea de TypeScript (lo contrario no es cierto). El diagrama anterior muestra que TypeScript le permite utilizar la próxima versión de JavaScript por adelantado.

Si TypeScript se basa en JavaScript, es imposible aprenderlo sin interesarse por este último y, más concretamente, por su estándar: ECMAScript. Está gestionado por una organización, ECMA, que se encarga de redactar y publicar especificaciones, al igual que el W3C (que produce, en particular, estándares web como HTML, CSS y Web API). Dentro de ECMA, hay varios grupos de trabajo, en particular TC39, que produce la especificación ECMAScript. Es una especificación que puede implementarse mediante lenguajes de scripting. El más conocido de ellos es JavaScript, pero el estándar ECMAScript se ha implementado en el pasado en otros lenguajes como JScript o ActionScript. Por tanto, es importante recordar que ECMAScript no es un lenguaje, sino una especificación. 

Además de conocer el estándar ECMAScript, es importante comprender también cómo funcionan los navegadores (Google Chrome, Mozilla Firefox, Microsoft Edge...). JavaScript es un lenguaje interpretado; esta tarea se delega al navegador, que incorpora un motor, también llamado máquina virtual (como la JVM en Java). Este motor debe implementar la especificación ECMAScript para poder interpretar correctamente el código JavaScript. Esto significa que, cada vez que se actualiza la especificación, las empresas que desarrollan un navegador deben actualizarlo con una nueva versión del motor JavaScript que implemente la última especificación ECMAScript.

images/01RI04.png

La primera versión de ECMAScript se lanzó en 1997 y sentó las bases para la especificación. La segunda versión salió al año siguiente y solo proponía una reorganización del documento. No ofrecía ninguna funcionalidad nueva. En 1999, ECMAScript 3 trajo muchas características innovadoras, incluyendo:

  • Gestión de excepciones con la llegada de bloques try y catch.

  • Mejor soporte para expresiones regulares.

  • Formato de los números.

Durante los siguientes ocho años, TC39 trabajó en una nueva versión extremadamente ambiciosa. El grupo quiere modernizar la programación JavaScript agregando muchos conceptos, como clases, interfaces, paquetes, tipado estático opcional... Por desgracia, en ese momento (2008), el lenguaje JavaScript estaba restringido al uso secundario en aplicaciones web. Se limita principalmente a configurar animaciones o ejecutar solicitudes AJAX (JavaScript asíncrono y XML). La mayor parte del desarrollo de aplicaciones se realiza en el lado del servidor. El TC39 considera que es demasiado complicado, para un lenguaje entonces considerado de segunda categoría, integrar todas estas innovaciones. Además, requeriría un esfuerzo considerable por parte de los proveedores de navegadores para actualizar su motor JavaScript.

La versión 4 de ECMAScript, y TC39 se centra en la versión 5, que corresponderá a una actualización de ECMAScript 3.

Esta nueva versión trae relativamente pocas características nuevas, que incluyen:

  • Modo estricto.

  • Descriptores de acceso get y set.

Dado que el desarrollo de las TI se produce en un mundo en constante evolución, el interés en JavaScript se reactivará a partir de 2009 gracias a:

  • El lanzamiento de la primera versión estable de Chrome en diciembre de 2008. Este navegador presenta un nuevo motor JavaScript particularmente eficiente y eficaz: V8. Tres años después, Chrome se convertirá en el navegador más utilizado...

¿Por qué TypeScript?

Antes de instalar cualquier herramienta o sumergirse en la arquitectura de TypeScript, es importante comprender sus dos funcionalidades principales: tipado estático y transpilación.

1. Transpilación

TypeScript le permite utilizar el JavaScript del mañana y ofrece transpilar el código. Pero ¿qué es la transpilación?

Este término designa un modo específico de compilación. En la mayoría de los casos, la compilación consiste en transformar el código fuente escrito con un lenguaje de programación en un programa ejecutable. La transpilación es diferente y más específica. Permite traducir el código fuente de un programa escrito en un primer lenguaje a un programa equivalente escrito en un segundo lenguaje que tenga el mismo nivel de abstracción. Por lo tanto, el compilador TypeScript compilará el código fuente de un proyecto en JavaScript. Además, puede hacer esto apuntando a versiones anteriores de JavaScript.

Uno de los beneficios de la transpilación es que facilita seguir la evolución de nuevas versiones de ECMAScript sin preocuparse por la versión del navegador que se utilizará para ejecutar el programa.

TypeScript, a través de su compilador, puede convertir el código a una versión inferior de JavaScript que será compatible con navegadores más antiguos o con aquellos que aún no han implementado el último estándar ECMAScript (esto se denomina downgrade). Esta es una ventaja interesante para las empresas que no siempre tienen la capacidad de mantenerse al día con las actualizaciones (algunos activos de TI son muy grandes y su migración es costosa). Esto también es una ventaja para los sitios dirigidos al público en general. Todavía hay muchos usuarios que navegan por la web con navegadores obsoletos. Por último, las nuevas funciones especificadas por el estándar ECMAScript pueden tardar varios meses en estar disponibles en los navegadores. En consecuencia, cuanto más reciente sea la versión de ECMAScript utilizada, más limitada resultará la compatibilidad. Sin embargo, muchos desarrolladores quieren utilizar las últimas novedades en lenguajes para poder tener un código actualizado y lo más optimizado posible. En definitiva, los transpiladores nacieron para superar estos problemas. Además, TypeScript no es el único transpilador disponible; cabe destacar Babel en particular, que es muy popular en la comunidad de JavaScript.

Cuidado con no confundir transpilación y Polyfill. Los Polyfills son scripts que emulan funciones que no están implementadas en un navegador. Por tanto, su objetivo es similar al de la transpilación, pero no lo realizan de la misma manera. Un Polyfill se evalúa en tiempo de ejecución; si el navegador no implementa la funcionalidad, la definirá.

A continuación se muestra un diagrama para ilustrar la diferencia de funcionamiento:

images/01RI08.png

TypeScript se puede configurar para que apunte a una versión de ECMAScript al traducir. Para hacer esto, debe especificar esta versión a través de la opción de compilación: target.

Ejemplo:

class Employee {  
  firstName: string;  
  age: number;  
  constructor(firstName: string, age: number) {  
    this.firstName = firstName;  
    this.age = age;  
  }  
}  
  
const employee1 = new Employee("Evelyn", 34); 

En este primer ejemplo, se define una clase Employee y se asigna una instancia de la clase a una variable declarada con la palabra clave const. Los conceptos de class y const solo existen desde ECMAScript 2015.

Estos dos conceptos se analizarán en detalle más adelante en el libro. Solo se utilizan aquí para ilustrar cómo funciona la transpilación.

Este código se puede transpilar a ECMAScript 5 mediante TypeScript. Para hacer esto, será necesario utilizar la opción de compilación target con el valor es5.

Ejemplo:

var Employee = /** @class */ (function () {  
    function Employee(firstName, age) {  
        this.firstName = firstName;  
        this.age = age;  
    }  ...

Los entresijos del tipado

1. Archivos de definición

TypeScript aplica un tipado estático a todo el código. Pero ¿qué pasa si queremos utilizar una biblioteca externa escrita en JavaScript y que, por tanto, no contiene tipado? Los archivos de definición están ahí para satisfacer esta necesidad.

Estos archivos (con la extensión .d.ts)describen los tipos correspondientes al código JavaScript que se utilizará. Para usar una biblioteca externa escrita en JavaScript en un proyecto que emplea TypeScript, debe recuperar el archivo de definición asociado con esta biblioteca. Una vez recuperada, la biblioteca se vuelve utilizable como si estuviera escrita en TypeScript y permite tener todas las funcionalidades integradas en el IDE (autocompletado, informe de errores, documentación en el editor...).

Los archivos de definición se utilizarán en el capítulo Un primer proyecto con Node.js.

Queda una pregunta: ¿cómo proporciona TypeScript el tipado en las funciones nativas de JavaScript?

Ejemplo (Visual Studio Code):

images/01RI12.png

El ejemplo anterior utiliza el objeto Math, que está definido de forma nativa en JavaScript. TypeScript interpreta correctamente este objeto y los tipos esperados. Además, Visual Studio Code ofrece autocompletado y documentación relacionada con este objeto, incluso si no se ha instalado ninguna definición para tipar el objeto. En realidad, TypeScript utiliza un archivo de definición que se incluye con el compilador. Llamado lib.d.ts, este archivo, en realidad, está compuesto por varios archivos de definición, cada uno con un alcance bien definido (ejemplo: lib.es5.d.ts para interoperabilidad con ECMAScript 5, lib.dom.d.ts para API relacionadas con la manipulación del DOM…). La opción de compilación lib le permite seleccionar los archivos de definición que compondrán los lib.d.ts utilizados por el compilador.

Las opciones de compilación se han abordado varias veces desde el comienzo de este capítulo sin haberlas explicado concretamente. Los detalles sobre las opciones básicas se verán en la sección Opciones de compilación.

2. Tipado estructural

Para comprender el sistema de tipos de TypeScript, es necesario entender la diferencia entre un sistema de tipos estructural (Structural Typing), un sistema de tipos nominal (Nominal Typing) y el Duck Typing. Estos sistemas permiten determinar la equivalencia y compatibilidad entre dos tipos.

En los sistemas de tipos nominal, los nombres de las declaraciones (interfaz, clases, etc.) tienen un impacto directo en la compatibilidad entre dos tipos. Un objeto de una clase denominada A no se puede asignar a un objeto de una clase denominada B incluso si estas dos clases tienen exactamente las mismas propiedades/métodos. Cuando se crean objetos de tipos anónimos, el compilador nombra estos tipos anónimos según las propiedades que poseen. Luego, utiliza estos nombres para comprobar la compatibilidad entre objetos. Lenguajes como C#, Java, PHP y C++ utilizan este sistema de tipos.

Ejemplo (C#):

public class Person  
{  
  public string Name { get; set; }  
  public int Age { get; set; }  
   
  public string GetInformation()  
  {  
    return this.Name + " - " + this.Age;  
  }  
}  
  
public class Employee  
{  
  public string Name { get; set; }  
  public int Age { get; set; }  
  
  public string GetInformation()  ...

La arquitectura de TypeScript

Una buena comprensión de la arquitectura de TypeScript le permitirá aprenderla correctamente, pero también comprender mejor su funcionamiento interno.

He aquí un diagrama que muestra la arquitectura macroscópica de TypeScript: 

images/01RI13.png

1. Core TypeScript Compiler

El Core TypeScript Compiler es el ladrillo que representa el compilador TypeScript. Es la pieza central de su arquitectura y su función es controlar y transpilar el código fuente. El compilador TypeScript se compone de elementos que se encuentran en la mayoría de los compiladores y cada uno de los cuales tiene un uso (Scanner, Parser, Binder, Emitter...).

Dos archivos son particularmente importantes:

  • checker.ts: verifica el código y puede devolver errores.

  • emitter.ts: transpila el código a JavaScript.

Para poder activar la compilación, el Core TypeScript Compiler necesita saber qué archivos compilar y las opciones de compilación. En la arquitectura TypeScript, esta información la proporciona el Languaje Service (servicio de lenguaje) o el Standalone TypeScript Compiler (compilador independiente de TypeScript).

2. Standalone TS Compiler

El Standalone TypeScript Compiler es una herramienta disponible en la línea de comandos (Command Line Interface), que le permite proporcionar al compilador una ruta a los archivos para compilar, así como opciones de compilación.

Esta herramienta está disponible después de instalar TypeScript en su entorno de desarrollo a través del alias tsc (consulte la sección Entorno de desarrollo).

3. Language Service

El Language Service se dedica a integrar TypeScript en los entornos de desarrollo. Este servicio está disponible después de instalar TypeScript y proporciona un conjunto de funciones que luego pueden ser utilizadas por los IDE (autocompletado, navegación de código, refactorización...). El servicio también ofrece asistencia para el desarrollo en forma de Quick Fixes.

Estos últimos ayudan a enriquecer la experiencia del desarrollador al ofrecer tareas automatizadas que resuelven un problema detectado en el código escrito en TypeScript (ejemplo: eliminar una variable no utilizada que fue detectada por el Language Service).

Este servicio es extensible y también permite agregar nuevas capacidades de análisis (ciertos plug-ins lo amplían, como Angular, Vue.js, GraphQL...).

4. Opciones de compilación

Como se indicó anteriormente, el compilador de TypeScript utiliza opciones de compilación. Estas influyen en cómo el compilador analiza y compila el código.

Se pueden proporcionar de diferentes formas:

  • A través de la terminal especificando los argumentos cuando se utiliza el Standalone TypeScript Compiler.

  • A través de un archivo de configuración que será leído por el Standalone TypeScript Compiler.

Se prefiere la segunda solución porque TypeScript tiene alrededor de cien opciones de compilación. Este archivo puede ser inicializado...

Entorno de desarrollo

1. Node.js

Node.js proporciona todas las herramientas necesarias para desarrollar una aplicación con TypeScript; por lo tanto, lo primero es instalarlo.

Node.js se puede descargar desde el sitio web oficial del proyecto: http://nodejs.org. Hay dos categorías de versiones disponibles:

  • La versión estable, llamada LTS (Last Stable Release).

  • La versión actual (esta última contiene las últimas funciones de Node.js).

images/01RI14N.png

Cualquiera que sea la versión que elija, no afectará la instalación de TypeScript. Una vez instalado Node.js, el comando npm estará disponible desde la terminal para administrar los paquetes de Node.js.

Un administrador de paquetes es una herramienta para administrar las dependencias de su proyecto. Los hay para todos los lenguajes: C# -> NuGet, Java -> Maven, PHP -> Composer, Ruby -> Gem… NPM es el administrador de paquetes para aplicaciones JavaScript.

Antes de continuar, es necesario verificar que Node.js y NPM sean accesibles desde la terminal. Para hacer esto, simplemente introduzca los siguientes comandos: 

node -v  
npm -v  

El resultado de ejecutar estos comandos debería mostrar el número de versión de ambas herramientas.

Si un mensaje de error indica que uno de los dos comandos no existe, es probable que la herramienta en cuestión falte en la variable de entorno «path» del sistema operativo.

2. Visual Studio Code

Visual Studio Code (también llamado VSCode) es un editor de código lanzado en abril de 2015 y desarrollado por Microsoft. Este editor multiplataforma y de código abierto (su código está disponible en GitHub: https://github.com/topics/visual-studio-code) se ha convertido en pocos años en uno de los entornos de desarrollo más populares entre los desarrolladores. Visual Studio Code es fácil de usar, altamente personalizable y desarrollado con TypeScript. Por lo tanto, tiene un muy buen soporte para el lenguaje (también se incluye una versión de TypeScript en el editor). Visual Studio Code es el editor al que se ha dado preferencia al escribir este libro, por lo que es necesario instalarlo antes de continuar. Se puede descargar desde el sitio web oficial del proyecto: https://code.visualstudio.com/

images/01RI15N.png

De entrada, Visual Studio Code ofrece relativamente pocos menús. Además de la barra de menú, tiene seis partes bien diferenciadas:

  • 1- Explorador: en esta parte se realizará la gestión de archivos y la escritura de código.

  • 2- Búsqueda: esta parte está dedicada a buscar dentro de todo lo que se ha cargado en el explorador.

  • 3- Control del código fuente: Visual Studio Code ofrece la posibilidad de utilizar un cliente gráfico para Git.

  • 4- Depuración: toda la configuración del depurador y el inicio de una sesión de depuración están disponibles en esta parte del editor.

  • 5- Extensiones: esta parte le permite gestionar extensiones (acceso al catálogo, instalación...).

  • 6- Configuración: da acceso a toda la configuración de Visual Studio Code.

images/01RI16N.png

Además de estas diferentes partes, Visual Studio Code contiene un conjunto de comandos que le permiten ejecutar tareas dentro del editor (ejemplo: formatear el código fuente, iniciar el depurador, hacer zoom en el editor...).

Se puede acceder a la interfaz de inicio de comandos a través del botón Configuración (el marcado con el número 6 en la imagen anterior) o mediante un atajo de teclado:

  • Para Windows/Linux: [Ctrl][Mayús] P

  • Para macOS: [Comando][Mayús] P

images/01RI17N.png

Antes de comenzar a desarrollar con TypeScript, es necesario tener algunos conocimientos básicos sobre cómo funcionan el explorador y el depurador.

El explorador se divide en varias partes:

  • 1- El explorador de código: este se divide en tres partes. La primera parte (Open Editors) enumera los archivos abiertos en el editor de texto. La segunda parte (File Explorer) representa la estructura de árbol del directorio o espacio de trabajo que se abrió con Visual Studio Code. La última parte (Outline) contiene el árbol de símbolos contenidos en el archivo abierto actualmente los tipos de símbolos varían según el tipo de archivo abierto).

  • 2- El editor de texto: es en esta parte donde se escribirá el código.

  • 3- Los Quick Fixes: están disponibles en el editor de texto y se representan por un «?» junto al número de línea de código. Proporcionan asistencia en el desarrollo, así como acceso a funcionalidades de «Refactoring» del código (refactorización en español).

images/01RI18N.png

La interfaz dedicada al depurador contiene tres partes importantes:

  • 1- La barra de inicio: permite iniciar una sesión de depuración. Se pueden crear varias configuraciones de depuración en Visual Studio Code; se deberá elegir la deseada a través de una lista desplegable antes de iniciar la sesión.

  • 2- Acceso a la configuración de depuración: si no hay ninguna configuración disponible, Visual Studio Code ofrecerá crear una nueva. De lo contrario, se abrirá el editor...