TypeScript mola

Desde la versión 0.9 vengo usando TypeScript en mis proyectos web, al principio solo lo usaba por el hecho usar la sintaxis de las clases y las interfaces, también por poder usar tipos en algunos casos, generalmente en parámetros de funciones de API y en el retorno de las mismas. También me fue de mucha utilidad, en su momento, para acercar a programadores de C# a JavaScript, al desarrollo en el browser.

Pero TypeScript es más que un JavaScript tipado, TypeScript te da la posibilidad de usar estándares EcmaScript de versiones que los navegadores todavía no implementan; las clases, los imports, los @decoradores, la desestructuración, … en fin, cosas que van saliendo en EcmaScript 6, 7 e incluso lo que se vaticina que traerá EcmaScript 8.

TypeScript consigue traernos futuras características de EcmaScript transpilando (traduciendo) TypeScript a EcmaScript 5. Supongo que no hace falta decir que el JavaScript actual que corren los navegadores es EcmaScript 5.

Prejuicios

Me sorprendió, al inicio, que la gente que programaba en JavaScript fuera tan reticente con TypeScript. Básicamente sentí que para ellos ponerle tipos a TypeScript era un atentado al dinamismo de javascript… he intentado explicar en más de una ocasión que TypeScript no te obliga a tipar las variables ni los objetos, puedes usar TypeScript sin especificar tipos, si es cierto que TypeScript, haciendo honor a su nombre, “adivina” los tipos sin que los especifiques, por ejemplo este código no compila:

var foo = "cadena";
foo = 2;

Si has declarado foo asignándole una cadena, TypeScript entiende que foo es string, y entonces no puedes asignarle un número, pero eso no significa que TypeScript no te permita asignarle cualquier valor a una variable, tienes estas otras dos opciones para hacerlo:

// Declarar la variable como "any"
var foo : any = "cadena";
foo = 2;
// Declarar la variable sin tipo y luego asignarle los valores
var bar;
bar = "cadena";
bar = 2;

Ambas cosas son lo mismo, puesto que TypeScript asigna el tipo any a las variables que no tienen tipo, es decir las variables any vienen siendo las variables de javascript de toda la vida. Si declaras una variable asignándole un valor TypeScript asigna el tipo del valor a la variable, pero si no asignas ningún valor la variable no tiene tipo y por lo tanto es una variable de tipo any.

Un ejemplo un poco más complejo:

var foo = { name: "Javier" };
foo.name = "Javi";
foo.surName = "Ros"; // Error
// Este código es equivalente al anterior:
interface Foo {
  name: string;
}
var foo : Foo = {};
foo.name = "Javi";
foo.surName = "Ros"; // Error
// Como lo hacemos?
var bar;   // O también:  
bar = {};  //      var bar : any = {};
bar.name = "Javi";
bar.surName = "Ros"; // Ahora si. 

Es decir, siempre podemos recurrir a declarar las variables sin tipo o con el tipo any para conservar el dinamismo de JavaScript.

TypeScript tiene una opción para el compilador que es --noImplicitAny, si pasamos ese parámetro entonces TypeScript no acepta que declares variables sin tipo y te obliga a tener que escribir el tipo siempre aunque sea any.

La otra parte que ponían como negativa los JavaScript coders con los que hablé fue el hecho de que typescript fuera transpilado, es decir escribes una cosa pero luego se ejecuta otra, en JavaScript estamos muy acostumbrados a depurar en el navegador y esto podía ser un inconveniente. A lo cual yo rebatí argumentando que casi todos usamos uglify o minimize y que usamos los source maps para poder depurar.

Pero bueno… con un poco de empatía podía entender que a la gente fuera reticente a esto, y bueno me resigné a que TypeScript no tendría tanto público como yo me pensaba. Aún así no fue motivo para que dejara de usar TypeScript, continué con él y con el sigo muy feliz.

Babel – O como a la gente se le hace el culo pepsi cola con EcmaScript 6

Resulta que mucho tiempo después de mis conversaciones con otro coders javascript, empiezo a ver por la web y sobre todo en GitHub muchos proyectos que empiezan a escribirse en usando EcmaScript 6, o más bien el denominado ES2015… pensé que lo mismo los navegadores ya lo soportaban y yo me había dormido, pero no, resulta que se usa un TRANSPILADOR llamado Babel, ahy amigooos!! Como le gusta la miel al oso. Al final mucha queja pero también estáis pasando por un transpilador y ya no ejecutáis el código que escribís.

Pero claro, ahora me vienen con que el código que genera Babel es más legible que el que genera TypeScript… muy bien chavales.

Quitando los tipos, hay pocas diferencias entre el código que acepta Babel y TypeScript, Babel va incorporando características de ES6/7 y TypeScript también, quizá uno incluya unas características antes que el otro o uno no incluya algo que el otro sí, pero más o menos van de la mano. Hay una diferencia que me llamó la atención, que Babel permitía hacer y TypeScript no, pensando que no tenía nada que ver con tipos me di cuenta de esto:

class Foo {
    constrcutor() {
        this.bar = "hola";
    }
}

Este código en Babel compila, sin embargo en TypeScript no, en TypeScript debes declarar bar como miembro de la clase:

class Foo {
    bar;
    constructor() {
        this.bar = "hola";
    }
}
// Lo que se puede reducir en:
class Foo {
    bar = "hola";
}

Pensé que no tenía nada que ver con los tipos, pero estaba equivocado, en TypeScript this es del tipo de la clase que se está definiendo, por lo tanto hay que definir bar en el tipo para poder asignar bar. O también podemos usar un casting:

class Foo {
    constrcutor() {
        (<any>this).bar = "hola"; // esto
        (this as any).bar = "hola"; // o esto
        // o esto:
        var self : any = this; 
        self.bar = "hola";
    }
}

En que nos pueden ayudar los tipos

Está muy bien que JavaScript sea dinámico todos hemos visto algo así:

var config = {
  url: "script.php",
  mehtod: "POST",
  data: { id : menuId },
  datatype: "html"
};

var request = $.ajax(config);

Hacemos una petición Ajax al servidor pasándole unos parámetros en el objeto config. Lo escribimos en JavaScript y ale, rular, pero no. El parámetro method está mal escrito es method y el parámetro datatype en realidad es dataType, está también mal escrito,… este error tonto es muy típico. Esto en TypeScript no pasa. La función a ajax está tipada, sería algo así:

interface IAjaxConfiguration {
    url?: string;
    method?: string;
    data?: any;
    dataType: string;
};

function ajax(config : IAjaxConfiguration) : IResponse;

Y entonces al realizar la llamada anterior usando mehtod y datatype nos daría un error en la llamada a $.ajax diciéndonos que el objeto config no implementa la interface IAjaxConfiguration. Aquí vemos como TypeScript te puede ayudar a no cometer el 50% de los errores que cometemos en JavaScript, puesto que casi siempre son por este tipo de errores.

Pero lo mejor de todo es que si no quieres tipar tu api puedes no hacerlo, basta con no usar tipos en las declaraciones de tus funciones o usar :any.

Por otro lado, TypeScript está en la versión 1.8.9, pronto saldrá la 1.9, y ha avanzado muchísimo desde que nació. Tiene infinidad de características que nos facilitan la programación lo más cercana a JavaScript. Por ejemplo algo que se usa muchísimo en javascript es pasar parámetros a funciones que pueden ser de distintos tipos, por ejemplo:

function something(log) {
    if (log) {
        if (typeof log === "string") {
            console.log(log);
        } else {
            console.log("something is called");
        }
    }
    ....
    ....
}

Es la típica función que acepta un parámetro que puede venir o no, y que si viene y es de un tipo determinado hacemos una cosa y si no pues otra, esta función en TypeScript sería:

function something(log? : boolean | string)

Con el símbolo ? hacemos que el parámetro sea opcional y así podemos no pasarlo en la llamada, y luego podemos declarar tantos tipos como aceptemos en la función separados por la barra vertical |.

Pero vamos que si te parece mal puedes usar la forma de siempre, no habrá problemas, pero considero que este tipo de cosas nos puede ayudar en muchas ocasiones y sobre todo cuando en un equipo de desarrollo hay varias personas y todas tienen que tocar código JavaScript.

Los typings

En TypeScript no podemos acceder a cosas que no han sido declaradas, así pues no podemos acceder a $ de jquery si no lo declaramos, esto no compila:

$('div').show();

Para poder usar $ debemos declararlo como un símbolo externo, esto se hace con declare:

declare var $;
$('div').show(); // Ahora si.

$ es declarado como any así que acepta cualquier cosa, ya tenemos acceso a jquery. Pero la gente ha ido más allá. Y si pudiéramos/quisiéramos acceder a JQuery de forma tipada, con intellisense y con chequeos de tipos?

interface IJQuery {
    show();
}

interface IJQueryStatic {
    (selector : string) : IJQuery;
    ajax(config : IAjaxConfiguration) : IResponse;    
}

declare var $ : IJQueryStatic;

Ya lo tenemos. Ahora podemos usar a JQuery de forma tipada:

$.ajax(config); // Ok
$("#name").show();
$("#name").hide(); // Error, IJQuery no define ningún método llamado "hide"
$("selector", context).show(); // Error IJQueryStatic solo acepta un parámetro.

Definiendo los Typings podemos facilitar el uso de nuestras librerías a terceros, además de que dispondremos del intellisense para ayudarnos a escribir el código.

Pero no, no deberás escribir los typings de cada librería que quieras usar de forma tipada, en un 90% de los casos ya están escritos. Existe un proyecto llamado Definitely typed donde se recopilan los typings de un mogollón de proyectos, en serio muchos y usando herramientas como Typings se pueden descargar fácilmente. Está casi todo, y para lo que no tengamos Typings pues podemos usar la opción de declare var sin tipo y a correr.

Cuando transpilas tu código con TypeScript puedes indicar que te cree los archivos .d.ts automáticamente. Esto hace que se generen como salida archivos .js y archivos .d.ts.

Si nada de esto te atrae e incluso ves cosas en contra, bien puedes continuar con Babel, ok, no tengo nada en contra. Pero claro… tu proyecto es open source, lo tienes en github y masmola mogollón, quieres darle tirón y que se use lo máximo posible y entonces… piensas que quieres que los usuarios de TypeScript lo usen. Entonces te pones a escribir los Typings…

Lo siento pero lo tengo que decir, cuando veo un proyecto escrito en Babel y luego veo que la gente se está escribiendo los typings… no se, pero para mi eso es de tontos… Lo único que te puede excusar de esto es que cuando has caído en que tienes que escribir typings ya tienes mucho código con Babel y puedes tener problemas migrando.

Para paliar esta situación, existe un proyecto llamado babel-dts-generator, no lo he probado, pero por ejemplo Aurelia lo usa, lo que hace es generar los archivos .d.ts a raíz de tu código Babel, al no probarlo no estoy seguro de cómo saca los tipos de las variables pero sospecho que te los adivina si usas JSDoc.

Conclusión

No encuentro motivos para usar un transpilador (Babel) antes que otro (TypeScript), aportando uno (TypeScript) más valor que otro (Babel). Por supuesto cada uno es libre de usar lo que quiera, pero me hace gracia usar un transpilador (Babel) y realizar un esfuerzo extra para que tu código sea más usable desde otro (TypeScript) pudiendo usar este último desde un principio. No veo motivos para temer por el dinamismo del lenguaje cuando TypeScript te permite ser o no ser más o menos rígido.

One comment

  • Que el equipo de google haya apostado por TypeScript en Angular2, dice mucho de este lenguaje, entre otras cosas que es un producto robusto por el que merece la pena apostar, pienso que para JavaScript es un gran avance.

    Un saludo.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

Demuestra que no eres un bot *