Typescript! Se acabó el coño de la Bernarda

Para los que ya pilotaban en Javascript, Typescript es innecesario, como cuando los programadores de C y Asm nos reíamos del C++ en los 90. Pero para empezar en la programación en el browser cuando vienes de C# o Java, TypeScript is your friend!

TypeScript nace como una iniciativa de Microsoft para domar a los programadores que se inician en la web estos últimos años (como es mi caso) y que Javascript les tira para atrás. Aunque no lo creamos existen muchos programadores que trabajan con aplicaciones web durante años y no dominan Javascript. En mi caso he estado varios años trabajando en una aplicación ASP.NET (Webforms con code-behind por supuesto) y no dominaba Javascript, vale que sabía hacer alguna cosa suelta o instalar un plugin de JQuery y usarlo, pero cuanto menos mejor, para mi Javascript siempre ha sido “el coño de la bernarda”, un lenguaje donde todo vale es muy útil para infinidad de cosas pero que puede volverte loco si no lo dominas y si no eres “estricto” cuando escribes mucho código o al menos tienes muchos ficheros js.

Con TypeScript Microsoft viene al rescate. Al igual que inventó WebForms para captar a los programadores que daban el salto a la web desde WinForms o Delphi y hacerles la vida más fácil en la web, ahora trae TypeScript para que los reacios a Javascript puedan escribir código en el browser en las aplicaciones MVC. Si me dicen esta última frase que he soltado antes de conocer TypeScript me hubiera echado las manos a la cabeza y hubiese tachado TypeScript de mi roadmap, … puesto que WebForms ha sido la gran metida del siglo con la que Microsoft nos engañó, ya que WebForms construía a “programadores web” sin que estos supieran que era la web, nos metía en un fregao de los guapos haciéndonos más tontos que pa qué! Por suerte eso acabó con la llegada de MVC, pero ¿no será TypeScript otra metida?

TypeScript es tan solo un lenguaje de programación con un compilador, el cual compila TypeScript a JavaScript, más concretamente a ECMAScript 5. Una vez compilado el Javascript resultante puede ser usado en nuestras páginas web. En mi caso lo uso en Visual Studio, el cual en la versión 2013 en adelante trae de serie el soporte para TypeScript. Los ficheros TypeScript tienen la extensión .ts y cuando los guardas desde Visual Studio los compila a Javascript obteniendo en el mismo directorio el archivo .js. Para el modo Debug también genera los archivos .map correspondientes de forma que la depuración de TypeScript se hace bastante fácil. Luego en tus páginas html o cshtml puedes incluir el archivo .js para ejecutarlo. Los ficheros .ts no llegan al servidor de producción, no se ejecutan en el servidor, tan solo son traducidos en tiempo de desarrollo a .js. Es el mismo modo de trabajo que se puede obtener cuando usamos Less CSS o SASS.

Dejar claro que TypeScript no es nada nuevo, está basado en ECMAScript 6, especificación de lenguaje que está madura pero veremos a ver con la guerra de navegadores que hay cuando llegará a ser ejecutado en los navegadores. La sintaxis de TypeScript esta copiada de ECMAScript 6, por lo tanto cuando llegue ECMAScript 6, TypeScript dejará de tener sentido y, si no me equivoco, me parece haber leído que será discontinuado cuando ECMAScript 6 esté implantado en los navegadores. Pero de momento Microsoft, bueno más bien ese simpático hombre que ha inventado los lenguajes de alto nivel que más me han gustado, Anders Hejlsberg, ha creado este engendro para captar a la gente que no soportaba Javascript por ser “el coño de la Bernarda”, y conmigo lo ha conseguido.

Para conocer el lenguaje y ver algunos ejemplos lo mejor es pasarse por su página web, tienen un Handbook que está muy bien para empezar y tienen publicada la especificación del lenguaje, aquí solo nombraré algunas cosas de las que más me gustan sin entrar en detalles. También decir que TypeScript puede ser usado tanto en NodeJs como en browser, en cuanto a NodeJs no tengo mucha idea … solo puedo hablar de lo que he usado para web.

Tipos

Por fin!!, no perdemos el que una variable pueda ser del tipo que sea, para ello tenemos el tipo any, pero si podemos obligar a otras a tener un tipo fijo. Ah! y también hay castings.

TypeScript Javascript
var nombre : string; // Cadena
nombre = 0; // Error
 
var nombre2 = "Hola" // Cadena, aún que no lo pongamos es string
 
var numero : number; // Numero
var numero2 : number = 2923; // Numero inicializado a 2923
numero = "Hola!"; // Error
 
var cosa : any = "Cadena bonita"; // any, aunque inicializada con un string.
cosa = 0; // Ok!!
cosa = "Cadena"; // Ok!!
var nombre;
nombre = 0; // Error no compilaría
 
var nombre2 = "Hola";
 
var numero;
var numero2 = 2923;
numero = "Hola!"; // Error no compilaría
 
var cosa = "Cadena bonita";
cosa = 0; // Ok!!
cosa = "Cadena"; // Ok!!

 

Clases

No me jodas!, para los que llegamos nuevos, desde C#, a la programación del cliente … no hay color.

TypeScript Javascript
class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}
 
var greeter = new Greeter("world");
 
var button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
    alert(greeter.greet());
}
 
document.body.appendChild(button);
var Greeter = (function () {
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
})();
 
var greeter = new Greeter("world");
 
var button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function () {
    alert(greeter.greet());
};
 
document.body.appendChild(button);

Módulos

Los hay internos y externos. Los internos los uso tan solo para separar mis clases, algo así:

TypeScript Javascript
module JRos.Libreria.Saludos {
    export class Greeter {
        greeting: string;
        constructor(message: string) {
            this.greeting = message;
        }
        greet() {
            return "Hello, " + this.greeting;
        }
    }
}
var greeter = new JRos.Libreria.Saludos.Greeter("world");
 
var button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
    alert(greeter.greet());
};
 
document.body.appendChild(button);
var JRos;
var JRos;
(function (JRos) {
    (function (Libreria) {
        (function (Saludos) {
            var Greeter = (function () {
                function Greeter(message) {
                    this.greeting = message;
                }
                Greeter.prototype.greet = function () {
                    return "Hello, " + this.greeting;
                };
                return Greeter;
            })();
            Saludos.Greeter = Greeter;
        })(Libreria.Saludos || (Libreria.Saludos = {}));
        var Saludos = Libreria.Saludos;
    })(JRos.Libreria || (JRos.Libreria = {}));
    var Libreria = JRos.Libreria;
})(JRos || (JRos = {}));
var greeter = new JRos.Libreria.Saludos.Greeter("world");
 
var button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function () {
    alert(greeter.greet());
};
 
document.body.appendChild(button);

Y luego tienes lo que llaman módulos externos, esto tiene que ver con AMD, en node.js lo implementan con CommonJS y en el browser con RequireJS, se trata de módulos externos que son cargados cuando alguien los requiere, para aprender sobre ello recomiendo conocer RequireJs y buscar en google “typescript amd”. Un ejemplo:

TypeScript Javascript
import ModuloExterno = require("OtroModuloExterno");
 
export class Greeter {
 greeting: string;
 constructor(message: string) {
 this.greeting = message;
 }
 greet() {
 return "Hello, " + this.greeting;
 }
}
 
export class OtraClase extends ModuloExterno.OtraClaseMas {
 public conSusAtributosYSuTipo : Greeter;
}
 
var greeter = new Sayings.Greeter("world");
 
var button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
 alert(greeter.greet());
};
 
document.body.appendChild(button);
var __extends = this.__extends || function (d, b) {
 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
 function __() { this.constructor = d; }
 __.prototype = b.prototype;
 d.prototype = new __();
};
define(["require", "exports", "OtroModuloExterno"], function(require, exports, ModuloExterno) {
 var Greeter = (function () {
 function Greeter(message) {
 this.greeting = message;
 }
 Greeter.prototype.greet = function () {
 return "Hello, " + this.greeting;
 };
 return Greeter;
 })();
 exports.Greeter = Greeter;
 
 var OtraClase = (function (_super) {
 __extends(OtraClase, _super);
 function OtraClase() {
 _super.apply(this, arguments);
 }
 return OtraClase;
 })(ModuloExterno.OtraClaseMas);
 exports.OtraClase = OtraClase;
 
 var greeter = new Sayings.Greeter("world");
 
 var button = document.createElement('button');
 button.textContent = "Say Hello";
 button.onclick = function () {
 alert(greeter.greet());
 };
 
 document.body.appendChild(button);
});

Como veis al compilar hace uso de RequireJs y por lo tanto si no cargas RequireJs no funciona, eso me gusta, intentan no reinventar la rueda y apoyarse en librerías conocidas por todos.

Interfaces

Me encantan para el tipado de objetos de entrada:

TypeScript Javascript
interface ISaludos {
 hola: string;
 adios?: string;
}
 
var saludosEspañol : ISaludos = { hola: "Hola", adios: "Adios"};
var saludosIngles : ISaludos = { hola: "Hi", adios: "Bye"};
var saludosCamperos : ISaludos = { hola: "yeha!"}; // "adios"" no es obligatorio (?)
 
function decirHola(saludos : ISaludos)
{
 alert(saludos.hola);
}
 
decirHola(saludosEspañol);
decirHola(saludosIngles);
decirHola(saludosCamperos);
 
decirHola({hola: "Ieeh!", adios: "vaya en paz!"}); // Funciona
 
decirHola({adios: "Hasta luego!"}); // Error "hola" es obligatorio.
var saludosEspañol = { hola: "Hola", adios: "Adios" };
var saludosIngles = { hola: "Hi", adios: "Bye" };
var saludosCamperos = { hola: "yeha!" };
 
function decirHola(saludos) {
 alert(saludos.hola);
}
 
decirHola(saludosEspañol);
decirHola(saludosIngles);
decirHola(saludosCamperos);
 
decirHola({ hola: "Ieeh!", adios: "vaya en paz!" }); // Funciona
 
decirHola({ adios: "Hasta luego!" }); // Error, no compilaría

 

 

Generics

Mis preferidos 😀

class Greeter<T> {
    greeting: T;
    constructor(message: T) {
        this.greeting = message;
    }
    greet() {
        return this.greeting;
    }
}
 
var greeter = new Greeter<string>("Hello, world");
 
var button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function () {
    alert(greeter.greet());
}
 
document.body.appendChild(button);

Para jugar un poco con todo esto tenemos el Playground de TypeScript donde te compila on line y puedes ver como traduce las cosas, también te señala los errores y te dice el porqué.

Update

Se me ha olvidado comentar algo muy importante. TypeScript es un super conjunto de Javascript, es decir, TypeScript añade cosas a Javascript, pero nuestro antiguo código Javascript sigue compilando bien, es decir Javascript está dentro de TypeScript, por lo tanto Typescript compila Javascript sin problemas (lo deja tal cual).

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 *