Aplicaciones modernas en JavaScript con TypeScript
TypeScript es un lenguaje de programación moderno que permite crear aplicaciones web robustas en JavaScript. TypeScript no requiere de ningún tipo de plugin, puesto que lo que hace es generar código JavaScript que se ejecuta en cualquier navegador, plataforma o sistema operativo.
Instalación
TypeScript viene dentro del paquete de actualización de Visual Studio 2013 Update 2, se puede descargar como paquete alternativo para Visual Studio 2012. También se puede instalar en Node-js como paquete para empezar a usarlo desde la línea de comandos.
npm install –g typescript
tsc helloworld.ts
Caracteristicas del lenguaje
TypeScript define varios tipos de datos extras además de los definidos en JavaScript. Cuando se hace una definición de tipo se tiene que poner un sufijo del tipo de datos en la definición, por ejemplo:
var isDone: boolean = false;
Boolean |
Number |
String |
var isDone: boolean = false; |
var height: number = 6; |
var name: string = "bob"; name = 'smith'; |
Array |
Enum |
Any |
var list:number[] = [1, 2, 3]; var list:Array<number> = [1, 2, 3]; |
enum Color {Red, Green, Blue}; var c: Color = Color.Green; |
var notSure: any = 4; notSure = "maybe a string instead"; notSure = false; // okay, definitely a Boolean |
Void |
|
|
function warnUser(): void { alert("This is my warning message"); } |
|
|
Interfaces
Una de las características principales de un lenguaje type-checking es que se enfoca en dar forma a los valores que tienen en tiempo de ejecución. Esto a veces se llama “duck subtyping”.
La mejor manera de ver cómo funcionan las interfaces es con un ejemplo:
function printLabel(labelledObj: {label: string}) {
console.log(labelledObj.label);
}
var myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
El type-checker comprueba que la llamada a printLabel, en esa llamada hay como requisito un parámetro labelledObj que es un objeto que como mínimo tiene una propiedad llamada label, de esta manera no hay forma de definir el tipo de la llamada.
Con TypeScrip se puede definir una interfaz para ese tipo de dato para asegurarnos de que el parámetro tenga como mínimo esa propiedad definida.
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
var myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
Además de definir las propiedades que puede tener un objeto a la hora de ser llamado en una función, también se puede definir las funciones que deberá implementar la clase que herede de la interfaz.
Aquí se puede ver una definición de una interfaz con un método:
interface SearchFunc {
(source: string, subString: string): boolean;
}
Así es como se define una función que implementa esa interfaz:
var mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
var result = source.search(subString);
if (result == -1) {
return false;
}
else {
return true;
}
}
Array Types
Lo mismo que se puede definir interfaces, también se pueden definir arrays.
interface StringArray {
[index: number]: string;
}
var myArray: StringArray;
myArray = ["Bob", "Fred"];
Clases
En TypeScript se pueden definir clases, que además también puede implementar las interfaces que previamente se han definido.
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
var cs: ClockStatic = Clock;
var newClock = new cs(7, 30);
También se puede hacer que una interfaz extienda otra interfaz, es decir que herede de ella.
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
var square = <Square>{};
square.color = "blue";
square.sideLength = 10;
Herencia de clases
También se puede definir herencia de clases definidas previamente.
class Animal {
name:string;
constructor(theName: string) { this.name = theName; }
move(meters: number) {
alert(this.name + " moved " + meters + "m.");
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
move() {
alert("Slithering...");
super.move(5);
}
}
class Horse extends Animal {
constructor(name: string) { super(name); }
move() {
alert("Galloping...");
super.move(45);
}
}
var sam = new Snake("Sammy the Python");
var tom: Animal = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);
La diferencia, a simple vista con C#, es que se utiliza la palabra reservada extends para definir cuando una clase está heredando de otra.
La visibilidad de todos los miembros es pública mientras no se especifique lo contrario.
Módulos
Otras de las características de TypeScript es la capacidad de definir módulos para que la funcionad se asile y se pueda reutilizar en cualquier momento.
Los módulos se pueden definir en un fichero o en varios fichero, de manera que el mismo modulo pueda estar repartido, para tener una parte core y otras partes que se puedan modificar sin tener que modificar el fichero principal.
module Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
var lettersRegexp = /^[A-Za-z]+$/;
var numberRegexp = /^[0-9]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: Validation.StringValidator; } = {};
validators['ZIP code'] = new Validation.ZipCodeValidator();
validators['Letters only'] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
for (var name in validators) {
console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches '
: ' does not match ') + name);
}
});
Una vez que se ha definido el módulo, el siguiente paso es usarlo en alguna otra parte del código, es muy parecido a como Node-js funciona y referencia paquetes.
import validation = require('./Validation');
var lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements validation.StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
Genericidad
Otra adición al lenguaje es el Soporte de genericidad en los tipos, que permite que el tipo sea otro parámetro para que así otro parámetro.
function identity<T>(arg: T): T {
return arg;
}
De esa manera las llamadas a esa función se puede hacer especificando el tipo o dejando al compilador que infiera el tipo en base al tipo del argumento.
var output = identity<string>("myString"); // type of output will be 'string'
var output = identity("myString"); // type of output will be 'string'
Herramientas
Visual Studio 2013 update 2 tiene Soporte directamente de TypeScript, con soporte de compilación, depuración e intellisense.
Para empezar con TypeScript está la web de https://www.typescriptlang.org/ de donde se puede encontrar ejemplos, y todo lo necesario para empezar con esta tecnología.
Luis Guerrero.
Technical Evangelist Microsoft Azure.