Share via


Aplicaciones modernas

Uso de TypeScript en las aplicaciones modernas

Rachel Appel

Rachel AppelEl propósito original de JavaScript era la manipulación del Modelo de objetos de documento (DOM) en un árbol DOM pequeño. Con el paso del tiempo, sin embargo, JavaScript se ha vuelto tan popular que ahora es un lenguaje predominante para cualquier tipo de aplicaciones, desde las pequeñas aplicaciones para los marketplace hasta las aplicaciones empresariales. A medida que la popularidad de JavaScript sigue creciendo, resulta inevitable un aumento en el número de herramientas y lenguajes que se necesitan para asistir a los desarrolladores. Uno de esos lenguajes es TypeScript. 

¿Qué es TypeScript y cómo funciona?

TypeScript es un superconjunto de JavaScript que permite escribir y generar código de JavaScript que opera de manera fuertemente tipada y orientada a objetos, pero que conserva esa flexibilidad que los desarrolladores adoran (o, en algunos casos, detestan) de JavaScript. TypeScript aumenta el margen de usos viables de JavaScript al campo de las aplicaciones empresariales, sitios web y aplicaciones en las que JavaScript históricamente se descarrila debido a la falta de herramientas en este espacio.

Tsc.exe es un compilador y generador de código para TypeScript de código abierto que se puede descargar en typescriptlang.org. TypeScript es un compilador independiente, así que podemos abrir un símbolo del sistema y ejecutar tsc.exe con los argumentos adecuados en cualquier momento; de la siguiente manera:

tsc.exe --out outputfile.js inputfile.ts

Podemos escribir código TypeScript, pasarlo por el compilador y el resultado será JavaScript de producción. Aunque TypeScript es un generador de código, no da como resultado código innecesario (lo que frecuentemente ocurre con las herramientas de diseño visual), no decora los nombres de las variables ni cambia el orden de las mismas. Esto significa que es mucho más sencillo depurar el producto final, ya que se trata de JavaScript convencional.

JavaScript ya es un lenguaje orientado a objetos, pero su sintaxis basada en prototipos desagrada a muchos desarrolladores. Para solucionar este problema, TypeScript incorpora ciertas características a JavaScript, como clases e interfaces, que son características propuestas del estándar ECMAScript 6 (ES6). Gracias a esto, TypeScript es un generador de código cubierto de azúcar sintáctico que, en la mayoría de los casos, reduce la cantidad de JavaScript del que tenemos que hacernos cargo. Por ejemplo, el siguiente fragmento usa la sintaxis basada en prototipos:

function Animal(name, species, habitat) {
  this.name = name;
  this.species = species;
  this.habitat = habitat;
}
Animal.prototype.sayHello = function(){
  console.log("RAWR!");
}
var animal =   new Animal("Fluffy", 
  "Velociraptor ", 
  "Everywhere. Run and hide.");
animal.sayHello();

El ejemplo anterior comienza con una función de constructor, un patrón de mucho uso en JavaScript y sin la definición de clase que normalmente veríamos en otros lenguajes orientados a objetos. Definimos las similitudes con los miembros de instancia de las clases en el interior de las funciones del constructor con la palabra clave this. Fuera de la función constructora reside el verdadero método prototipo, que enlaza los métodos JavaScript con las clases. Las clases de TypeScript nos permiten escribir el mismo código del ejemplo anterior, pero con una sintaxis más natural, como se aprecia en la Figura 1.

Figura 1 Una clase en TypeScript

class Animal
{  
  name: string;
  species: string;
  habitat: string;
  constructor(name: string, species: string, habitat: string)
  {
    this.name = name;
    this.species = species;
    this.habitat = habitat;
  }
  sayhello()
  {
    Console.log("RAWR");
  }
}

Para muchos desarrolladores, el ejemplo de código en TypeScript de la Figura 1 se lee más fácil que el equivalente en JavaScript tradicional. No cabe duda de que el código sirve como una definición de clase con un listado de miembros y también muestra los tipos de los argumentos. Además, TypeScript proporciona comprobación de tipos, interfaces, comprobación estática en tiempo de compilación, expresiones tipo lambda y otros extras que generalmente se encuentran en los lenguajes compilados (no interpretados). Estas extensiones al lenguaje JavaScript son beneficiosas, ya que evitan que caigamos en las trampas de programación típicas.

Otros desafíos típicos de JavaScript surgen cuando existen demasiadas variables con alcance público en el espacio de nombres global de JavaScript, lo que contamina el espacio de nombres global (esto parece ocurrir con demasiada frecuencia). Afortunadamente, TypeScript ayuda en este caso, ya que implementa módulos que se comportan como espacios de nombres y crea clausuras que evitan esa acumulación global de elementos. Existen dos tipos de módulos en TypeScript: los internos y los externos. Los módulos internos contienen código que se declara en el archivo actual y tenemos que importar los módulos externos al agregar ///<reference path=‘ruta/archivo-de-referencia.ts’ /> en la parte superior del archivo de código actual. Para declarar módulos basta con la palabra clave module, con llaves para cerrar. Los módulos de TypeScript tienen un aspecto similar al este:

module outerModule {
  "use strict";
  module innerModule {
    export function aFunction { s: string };
    export var variable = 1;
  }
}

Y el JavaScript que se emite se parecerá a esto:

var outerModule;
(function (outerModule) {
  "use strict";
  var innerModule;
  (function (innerModule) {
    function aFunction() { s: string }
    innerModule.aFunction = aFunction;
    innerModule.variable = 1;
  })(innerModule || (innerModule = {}));
})(outerModule || (outerModule = {}));

El código anterior crea una instancia de módulo singleton, a la que se puede acceder desde cualquier lugar de una aplicación de la Tienda Windows en el espacio de nombres outerModule. Como puede ver, los módulos se representan por funciones anónimas (es decir, expresiones de función invocadas inmediatamente o IIFE). Cualquier miembro que se haya marcado con la directiva export tiene alcance global, que es equivalente a los miembros de C# que se marcan con la palabra clave internal (es decir, en todo el proyecto).

Configuración y creación de aplicaciones para la Tienda Windows con TypeScript

Existe una integración total entre TypeScript y Visual Studio, pero TypeScript se distribuye por separado, así que deberá instalar las siguientes herramientas además de las ediciones Visual Studio 2012 Express, Pro o Ultimate:

Una vez que las extensiones estén instaladas, podrá encontrar una plantilla de proyecto TypeScript para Visual Studio, ubicada justo debajo del nodo JavaScript en el cuadro de diálogo Nuevo proyecto. Esta plantilla integrada específica es una plantilla de aplicación web para cliente HTML que integra los activos TypeScript adecuados, por lo que no tiene que hacer nada más para que funcione.

Incluso con la integración estrecha entre Visual Studio y TypeScript, a la hora de redactar este artículo no hay plantillas de proyecto integradas de TypeScript para la Tienda Windows (solo la plantilla web para cliente que se mencionó anteriormente), pero la documentación de TypeScript menciona que aparecerán pronto. Mientras tanto, si está desarrollando aplicaciones para la Tienda Windows con JavaScript, puede usar cualquiera de las plantillas de proyecto actuales de JavaScript, como En blanco, Cuadrícula, Dividida, entre otras. TypeScript funciona automáticamente con todas ellas, pero deberá realizar algunas modificaciones menores en el proyecto para que funcionen. 

Para integrar TypeScript en una aplicación existente para la Tienda Windows, debe copiar los siguientes archivos de declaración a una carpeta como, por ejemplo, <raíz-del-proyecto>\tslib:

  • lib.d.ts
  • winjs.d.ts
  • winrt.d.ts

Estos archivos están disponibles en la página de descarga de TypeScript, en typescript.codeplex.com. Observe que las extensiones de los archivos mencionados terminan en .d.ts, donde “d” representa “declaración”. Estos archivos contienen declaraciones de tipo para marcos populares como jQuery y las bibliotecas nativas de Windows en tiempo de ejecución (WinRT) y Biblioteca de Windows para JavaScript (WinJS). La Figura 2 contiene un ejemplo del archivo winjs.d.ts que describe los métodos de WinJS que más se usan. Observe que el archivo está lleno de declaraciones públicas que Visual Studio y otras herramientas usan para las comprobaciones en tiempo de compilación. Como en este momento TypeScript todavía es un poco inmaduro, podrían faltar algunas, pero usted mismo puede agregarlas.

Figura 2 Análisis del archivo de definición winjs.d.ts

declare module WinJS {
  export function strictProcessing(): void;
  export module Binding {
    export function as(data: any): any;
    export class List {
      constructor (data: any[]);
      public push(item: any): any;
      public indexOf(item: any): number;
      public splice(index: number, count: number, newelems: any[]): any[];
      public splice(index: number, count: number): any[];
      public splice(index: number): any[];
      public createFiltered(predicate: (x: any) => bool): List;
      public createGrouped(keySelector: (x: any) => any, dataSelector:
         (x: any) => any): List;
        public groups: any;
        public dataSource: any;
        public getAt: any;
      }
      export var optimizeBindingReferences: bool;
  }
  export module Namespace {
    export var define: any;
    export var defineWithParent: any;
  }
  export module Class {
    export function define(constructor: any, instanceMembers: any): any;
    export function derive(
      baseClass: any, constructor: any, instanceMembers: any): any;
    export function mix(constructor: any, mixin: any): any;
  }
  export function xhr(options: { type: string; url: string; user: string;
     password: string; headers: any; data: any;
     responseType: string; }): WinJS.Promise;
  export module Application {
    export interface IOHelper {
      exists(filename: string): bool;
      readText(fileName: string, def: string): WinJS.Promise;
      readText(fileName: string): WinJS.Promise;
      writeText(fileName: string, text: string): WinJS.Promise;
      remove(fileName: string): WinJS.Promise;
    }
// More definitions

Los programadores que escriben aplicaciones WinJS deberían estar familiarizados con estos métodos auxiliares, como los objetos WinJS.Binding.List y WinJS.xhr; todos los métodos auxiliares de las bibliotecas WinRT y WinJS se encuentran a su disposición. Estos archivos de definición permiten que IntelliSense funcione en Visual Studio.

Cuando agregamos un archivo .ts a cualquier archivo del proyecto, Visual Studio crea automáticamente los archivos complementarios .js y .min.js (minimizado) correspondientes. TypeScript vuelve a crear estos archivos cada vez que guardamos un archivo .ts en Visual Studio.

En la mayoría de las plantillas JavaScript de la Tienda Windows, la carpeta llamada pages contiene subcarpetas con los activos .html, .css y .js colectivos necesarios para cada página. Aparte de estos, la carpeta \js contiene otros archivos JavaScript, como data.js, default.js y navigator.js. Debemos integrar TypeScript en estos archivos mediante los siguientes pasos, para cada uno:

  1. Agregamos referencias de declaración a la parte superior de cada archivo. Por ejemplo: ///<reference path=‘ruta/archivo-de-referencia.ts’ />.
  2. Cambiamos la extensión de los archivos de .js a .ts.
  3. Modificamos el código JavaScript existente a las construcciones correspondientes del lenguaje TypeScript: módulos, clases, declaraciones, etcétera.

Por ejemplo, para integrar \js\data.js, tenemos que insertar referencias en la parte superior del archivo y convertir la función de nivel superior a un módulo similar al que se muestra en la Figura 3. Si cambiamos el nombre de data.js a data.ts, Visual Studio creará los archivos .js y de asignación correspondientes cuando guardamos el archivo.

Figura 3 Transformación TypeScript de data.js a data.ts

// Original code in data.js
(function () {
  "use strict";
  var list = new WinJS.Binding.List();
  var groupedItems = list.createGrouped(
    function groupKeySelector(item) { return item.group.key; },
    function groupDataSelector(item) { return item.group; }
  );
  // TODO: Replace the data with your real data
  // You can add data from asynchronous sources
  // whenever it becomes available
  generateSampleData().forEach(function (item) {
    list.push(item);
  });
  // ... More data-access code
})();
// The modified data.ts file
///<reference path='../ts/winjs.d.ts' />
///<reference path='../ts/winrt.d.ts' />
  module TypeScriptApp {
    "use strict";
    var list = new WinJS.Binding.List();
    var groupedItems = list.createGrouped(
      function groupKeySelector(item) { return item.group.key; },
      function groupDataSelector(item) { return item.group; }
  );
  // TODO: Replace the data with your real data.
  // You can add data from asynchronous sources whenever it becomes available
  generateSampleData().forEach(function (item) {
    list.push(item);
  });
  // ... More data-access code
}

El código de la Figura 3 actúa como un espacio de nombres de nivel superior (módulo) que emplea el nombre del proyecto (TypeScriptApp), respetando así las convenciones estándar familiares para los usuarios de Visual Studio.

Naturalmente, podemos dejar tal cual el código JavaScript actual de las plantillas y este se ejecutará como previsto, pero no será coherente con el estilo y la sintaxis, lo que podría dificultar el mantenimiento.

Opciones de Visual Studio para TypeScript

Existen algunas configuración que tiene que conocer para poder hacer un uso óptimo de TypeScript, especialmente en las aplicaciones para la Tienda Windows. Como los archivos .js minimizados no son necesarios para las aplicaciones de la Tienda Windows, puede cambiar la opción “Minimizar JavaScript generado” a Falso, en la pestaña Web Essentials del cuadro de diálogo Herramientas de Visual Studio | Opciones, y eliminar cualquiera que exista. Los archivos minimizados solo mejoran el rendimiento en los sitios web, no en las aplicaciones cliente, porque disminuyen el ancho de banda total a través de Internet.

Otro cambio necesario para usar TypeScript en las aplicaciones de la Tienda Windows es establecer la codificación a “Volver a guardar JS con BOM de UTF-8” (consultar bit.ly/ceKkYq) en el cuadro de diálogo de Herramientas | Opciones. Al establecer la BOM (marca de orden de bytes) de UTF-8, la aplicación se desempeña mejor durante el inicio y, de esta forma, observa las instrucciones para la administración del ciclo de vida del proceso de la Tienda Windows (consulte mi columna en la edición especial sobre Windows 8: “Ciclo de vida de las aplicaciones para la Tienda Windows”, en msdn.microsoft.com/magazine/jj660301 para obtener más información sobre estas instrucciones). Además del rendimiento, esta especificación de codificación es obligatoria para aprobar la certificación de la Tienda Windows y para publicar la aplicación.

Los desarrolladores de JavaScript saben que las herramientas como los mapas de código fuente son una necesidad en la depuración del código implementado o el código fuente de los generadores de JavaScript. La razón es que los mapas de código fuente son archivos que asignan código con otro código, frecuentemente entre archivos de desarrollo de tamaño estándar y archivos de producción minimizados y combinados que son difíciles de depurar. Establezca la opción “Generar mapa de origen” en Verdadero en Visual Studio; esto le permitirá crear mapas de código fuente entre TypeScript y JavaScript para habilitar la depuración de TypeScript. Esta opción aplica el modificador --sourcemap del compilador, que a su vez crea los mapas en tiempo de compilación.

De manera predeterminada, el compilador de TypeScript genera código compatible con ECMAScript 3 (ES3), pero también podemos compilar a ECMAScript 5 (ES5) si cambiamos la opción “Compilar a ECMAScript 3” a Falso en Visual Studio, lo que establece el modificador --target del compilador tsc, para que genere código en ES5. Los desarrolladores que quieran usar una sintaxis con propiedades o cualquier característica de ES5 o propuesta para TypeScript ES6, deberían establecer este modificador.

Beneficios adicionales

JavaScript llegó para quedarse y es más popular que nunca, así que los desarrolladores que llegan a JavaScript desde la tierra de los lenguajes compilados, ahora cuentan con la ayuda de TypeScript para escribir y administrar código JavaScript de tamaño de aplicaciones. Los desarrolladores de JavaScript se benefician de la comprobación de tipos extra y de los servicios del compilador a los que normalmente no tienen acceso cuando escriben directamente en JavaScript.

Rachel Appel es evangelizadora de desarrollo en Microsoft en la ciudad de Nueva York. Puede ubicarla en su sitio web en rachelappel.com o por correo electrónico en rachel.appel@microsoft.com. También puede seguir sus últimas actualizaciones en Twitter en twitter.com/rachelappel.

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Christopher Bennage (Microsoft)
Christopher Bennage (Microsoft)

Christopher Bennage es desarrollador en el equipo de Patrones y procedimientos de Microsoft. Su trabajo es descubrir, recopilar y fomentar las prácticas que le alegran la vida a los desarrolladores. Entre sus intereses técnicos más recientes se encuentran JavaScript y el desarrollo (informal) de juegos. Mantiene un blog en dev.bennage.com.