Tutoriales

TypeScript es un lenguaje de programación moderno que permite crear aplicaciones web robustas en JavaScript utilizando herramientas de POO (Programación Orientada a Objetos). 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. Es un superset de JavaScript, que esencialmente añade tipos estáticos y objetos basados en clases.

Wheater Dasboard: Angular + OpenWeather
Publicidad
Wheater Dasboard: Angular + OpenWeather by Victor Valencia Rico

Tabla de contenido

Introducción

TypeScript es un lenguaje de programación libre y de código abierto desarrollado y mantenido por Microsoft. Anders Hejlsberg, diseñador de C# y creador de Delphi y Turbo Pascal, ha trabajado en el desarrollo de TypeScript.

TypeScript extiende la sintaxis de JavaScript, por tanto cualquier código JavaScript existente debería funcionar sin problemas. Está pensado para grandes proyectos, los cuales a través de un compilador de TypeScript se traducen a código JavaScript original.

TypeScript en realidad es un compilador que se encarga de traducir las instrucciones de un lenguaje a otro, aqui lo llamaremos también pre-compilador ya que este realmente intenta realizar las funciones de un compilandor más las funciones de un traductor de instrucciones.

Requerimientos

La instalación de TypeScript es relativamente simple, únicamente necesitamos la instalación de NodeJS y junto con el gestor de paquetes npm para descargar TypeScript:

node >= 8.0 o mayor

$ node --version

npm >= 5.0 o mayor

$ npm --version
Angular App Tool: Digitalize polygons
Publicidad
Angular App Tool: Digitalize polygons by Victor Valencia Rico

Instalación de TypeScript

Ahora instalamos TypeScript de manera global:

$ npm i -g typescript

Para comprobar la correcta instalación de TypeScript y la versión que se ha instalado escribimos:

$ tsc --version

En este tutorial la versión instalada de TypeScript es v3.8

El siguiente paso será crear una carpeta donde trabajar para ello, la cual llamaremos TypeScript, una vez creada navegaremos a través de la terminal a la carpeta recién creada y escribiremos el siguiente comando:


$ cd TypeScript
$ tsc --init
  

Con este comando generaremos el archivo de configuración básico que utilizará TypeScript para compilar la información, llamado tsconfig.json.


//tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  }
}
  

TypeScript en Acción

Para iniciar con TypeScript realizaremos el primer ejemplo y lo llamaremos hello-world.ts:


//hello-world.ts
console.log("Hello World...");
  

Para que secompile un archivo de TypeScript se tiene que utilizar el siguiente comando:

$ tsc hello-world.ts

Esta acción generará un archivo con la extensión .js, para este ejemplo se llamará hello-world.js:


//hello-world.js
"use strict";
console.log("Hello World...");
  

Para ejecutar este script en nuestra terminal usaremos NodeJs de la siguiente manera:

$ node hello-world.js
# Hello World...
  

Ahora se preguntarán, ¿siempre que haga una modificacion a mi archivo .ts tengo que ejercutar el comando $ tsc hello-world.ts?, no se preocupen, para no tener que realizar esto siempre existe el siguiente comando:

$ tsc --watch

Este comando ejecuta el compilador de TypeScript en modo --watch. Se mantiene al tanto de algún cambio en los archivos de entrada y activa la recompilación de todos los archivos .ts dentro del directorio que tengan algún cambio.

Angular App: Todo List
Publicidad
Angular App: Todo List by Victor Valencia Rico

Tipos de datos

TypeScript es un lenguaje que añade a JavaScript una capa de tipado estático y algunas otras incorporaciones de POO tradicional. Esta capa puede resultarnos de muchísima ayuda durante el desarrollo. Sin embargo, todas estas características son simplemente para ayudar a trabajar con JavaScript en tiempo de diseño, ya que TypeScript compila todo como JavaScript tradicional.

Tipado estático o fuertemente tipado: Se debe de definir el tipo de dato, obligando a que no pueda haber errores con los tipos de datos (TypeScript).


//TypeScript
function printName (name: string) {
  console.log(name);
}
printName(); //Error: An argument for 'name' was not provided
  

Tipado dinámico o débilmente tipado: No se deben definir o no tiene porque especificar el tipo de dato (PHP, Javascript).


//JavaScript
function printName (name) {
  console.log(name);
}
printName(); //Resultado: undefined
  

Tipos primitivos

  • Boolean

    El tipo de dato más básico es el valor true/false, que JavaScript y TypeScript llaman un valor booleano.

    
    let isVisible : boolean = false;
          
  • Number

    Como en JavaScript, todos los números en TypeScript son valores decimales. Estos números decimales obtienen el tipo number. Además de los hexadecimales y decimales, TypeScript también admite binarios y octales introducidos en ECMAScript 2015.

    
    let integer: number = 6;
    let decimal: number = 4.20;
    let hex: number = 0xf00d;
    let binary: number = 0b1010;
    let octal: number = 0o744;
          
  • String

    Otra parte fundamental de la creación de programas en JavaScript para páginas web y servidores es trabajar con datos textuales o cadenas. Como en otros idiomas, usamos el tipo string para referirnos a estos tipos de datos. Al igual que JavaScript, TypeScript también utiliza comillas dobles " o comillas simples ' para delimitar los datos de tipo string.

    
    let color: string = "green";
    color = 'blue';
          

    También se pueden usar los templates string o plantillas, que pueden abarcar varias líneas y tener expresiones incrustadas. Estas cadenas están delimitadas por el carácter backtick/backquote `, y las expresiones incrustadas tienen la forma ${ expr }.

    
          

    Esto es equivalente a:

    
    let sentence: string = "Hello, my name is " + fullName + ".
    
    "
    + "I'll be " + (age + 1) + " years old next year.";                
          
  • Array

    TypeScript, como JavaScript, le permite trabajar con arrays de valores. Los tipos de arrays se pueden escribir de una de dos maneras.

    En el primero, se usa el tipo de elementos seguido de [] para denotar un array de ese tipo de elemento:

    
    let list: number[] = [1, 2, 3, 4];
          

    La segunda forma usa un tipo de array genérico, Array<elemType>:

    
    let list: Array<number> = [1, 2, 3, 4];          
          
  • Tuple

    Los tipos tuple o tupla permiten expresar un array con un número fijo de elementos cuyos tipos son conocidos, pero no necesitan ser los mismos. Por ejemplo, es posible que desee representar un valor como un par: string, number.

    
    let x: [string, number]; // Declarar el tipo tuple
    // Inicializar la variable x
    x = ["hello", 10]; // OK 
    x = [10, "hello"]; // Error        
          

    Al acceder a un elemento con un índice conocido, se recupera el tipo correcto:

    
    console.log(x[0].substring(1)); // OK
    console.log(x[1].substring(1)); // Error, 'number' no tiene 'substring'  
    x[3] = "world"; // Error, Propiedad '3' no existe en el tipo '[string, number]'.  
          
  • Enum

    Una adición útil al conjunto estándar de tipos de datos de JavaScript son los enum o enumeraciónes. Como en lenguajes como C#, una enumeración es una forma de dar nombres más amigables a conjuntos de valores numéricos.

    
    enum Color {Red, Green, Blue}
    let c: Color = Color.Green;        
          

    De forma predeterminada, las enumeraciones comienzan a numerar sus miembros a partir de 0. Puede cambiar esto configurando manualmente el valor de uno de sus miembros. Por ejemplo, podemos comenzar el ejemplo anterior en 1, en lugar de 0:

    
    enum Color {Red = 1, Green, Blue}
          

    O, incluso establezca manualmente todos los valores en la enumeración:

    
    enum Color {Red = 1, Green = 2, Blue = 5}
          

    Una característica útil de las enumeraciones es que también puede pasar de un valor numérico al nombre de ese valor en la enumeración. Por ejemplo, si tuviéramos el valor 3 pero no estuviéramos seguros de a qué se asignó en la enumeración de color anterior, podríamos buscar el nombre correspondiente:

    
    enum Color {Red = 1, Green, Blue}
    let colorName: string = Color[3];
    console.log(colorName); // Muestra 'Blue' ya que su valor es el 3
          
  • Any

    Es posible que necesitemos describir el tipo de variables que no sabemos cuando estamos escribiendo una solicitud. Estos valores pueden provenir de contenido dinámico, por ejemplo, del usuario o de una biblioteca de terceros. En estos casos, queremos inhabilitar la verificación de tipos y dejar que los valores pasen por las comprobaciones en tiempo de compilación. Para hacerlo, los etiquetamos con el tipo any:

    
    let notSure: any = 4;
    notSure = "maybe a string";
    notSure = false; // OK, Definitivamente es un boolean
          
  • Void

    El tipo void es un poco como lo opuesto a any: la ausencia de tener cualquier tipo. Por lo general, puede ver esto como el tipo de retorno de funciones que no devuelven un valor:

    
    function print(): void {
      console.log("Print message");
    }        
          
  • Null y Undefined

    En TypeScript, tanto undefined como null en realidad tienen sus propios tipos llamados undefined y null respectivamente. Al igual que void, no son extremadamente útiles por sí solos:

    
    // ¡No hay mucho más que podamos asignar a estas variables!
    let u: undefined = undefined;
    let n: null = null;        
          
  • Never

    El tipo never representa el tipo de valores que nunca ocurren. Por ejemplo, never es el tipo de retorno para una expresión que siempre arroja una excepción o una que nunca regresa.

    Algunos ejemplos de funciones que nunca regresan:

    
    // La función de retorno nunca debe tener un punto final inalcanzable
    function error(message: string): never {
      throw new Error(message);
    }
    // Otro ejemplo
    function infiniteLoop(): never {
      while (true) { }
    }        
          
  • Object

    object es un tipo que representa el tipo no primitivo, es decir, cualquier cosa que no sea number, string, boolean, bigint, symbol, null o undefined.

Angular App Tool: Digitalize polygons
Publicidad
Angular App Tool: Digitalize polygons by Victor Valencia Rico

Interfaces

Uno de los principios básicos de TypeScript es que la verificación de tipos se centra en la forma que tienen los valores. Esto a veces llamado duck typing o structural subtyping. En TypeScript, las interfaces cumplen la función de nombrar estos tipos y son una forma poderosa de definir contratos dentro de su código, así como contratos con código fuera de su proyecto.

La forma más fácil de ver cómo funcionan las interfaces es comenzar con un ejemplo simple llamado interface.ts:


//interface.ts
interface Person {
  firstName: string;
  lastName: string;  
}

function greeter(person: Person) {
  console.log("Hello, " + person.firstName + " " + person.lastName);
}

var user = { firstName: "Victor", lastName: "Valencia" }; 
greeter(user);
  

Para que se compile el archivo de TypeScript y posteriormente se ejecute se puede utilizar la siguiente combinación de comandos. Compilamos el archivo interface.ts y ejecutamos el archivo generado interface.js:


$ tsc interface.ts | node interface.js
# Hello, Victor Valencia    
  

La interfaz Person es un nombre que ahora podemos usar para describir el requisito en el ejemplo anterior. Contiene 2 propiedades llamadas firstName y lastName de tipo string. Tenga en cuenta que no teníamos que decir explícitamente que el objeto que pasamos a la función greeter() implementa esta interfaz como podríamos tener que hacerlo en otros idiomas. Aquí, lo único que importa es la forma. Si el objeto que pasamos a la función cumple con los requisitos enumerados, entonces está permitido.

No todas las propiedades de una interfaz pueden ser necesarias. Algunos existen bajo ciertas condiciones o pueden no estar allí en absoluto. Estas propiedades opcionales son populares cuando se crean patrones como option bags donde se pasa un objeto a una función que solo tiene un par de propiedades completadas.

Aquí hay un ejemplo de este patrón:


//interface.ts
interface Person {
  firstName: string;
  lastName?: string;
}

function greeter(person: Person) {
  if(person.lastName)
    console.log("Hello, " + person.firstName + " " + person.lastName);
  else
    console.log("Hello, " + person.firstName);
}

var user = { firstName: "Victor", lastName: "Valencia" };
greeter(user);
greeter({ firstName: "Mark" });
  

Compilamos el archivo interface.ts y ejecutamos el archivo generado interface.js:


$ tsc interface.ts | node interface.js
# Hello, Victor Valencia    
# Hello, Mark
  

El símbolo de interrogación ? al final del nombre de la variable indica que esa propiedad es opcional.

Funciones

Para comenzar, al igual que en JavaScript, las funciones de TypeScript se pueden crear como una función con nombre o como una función anónima. Esto le permite elegir el enfoque más apropiado para su aplicación, ya sea que esté creando una lista de funciones en una API o una función única para pasar a otra función.

Para recapitular rápidamente cómo se ven estos dos enfoques en JavaScript:


// Función con nombre
function add(x, y) {
  return x + y;
}

// Función anónima
let myAdd = function(x, y) { return x + y; };
  

Ahora con TypeScript podemos agregar tipos a nuestro ejemplo anterior:


// Función con nombre
function add(x: number, y: number): number {
  return x + y;
}

// Función anónima
let myAdd = function(x: number, y: number): number { return x + y; };
  

Podemos agregar tipos a cada uno de los parámetros y luego a la función misma para agregar un tipo al valor retornado. TypeScript puede calcular el tipo del valor retornado al observar las declaraciones de retorno.

En TypeScript, en las funciones el número de argumentos tiene que coincidir con el número de parámetros que la función espera. En JavaScript, cada parámetro es opcional, y los usuarios pueden dejarlos como mejor les parezca. Cuando lo hacen, su valor es undefined. Podemos obtener esta funcionalidad en TypeScript agregando el símbolo de interrogación ? al final de los parámetros para hacerlos opcionales. De la misma manera como en las interfaces.


//function.ts
function buildName(firstName: string, lastName?: string) : string {
  if (lastName)
    return firstName + " " + lastName;
  else
    return firstName;
}

console.log(buildName("Victor", "Valencia"));
console.log(buildName("Santiago"));
  

Compilamos el archivo function.ts y ejecutamos el archivo generado function.js:


$ tsc function.ts | node function.js
# Victor Valencia
# Santiago
  

En TypeScript, también podemos establecer un valor que se asignará a un parámetro si el usuario no proporciona uno, o si el usuario pasa undefined en su lugar. Estos se denominan parámetros inicializados por defecto:


//function.ts
function buildName(firstName: string, lastName = "Valencia") : string {
  return firstName + " " + lastName;
}

console.log(buildName("Victor", "Valencia"));
console.log(buildName("Rosa", undefined));
console.log(buildName("Santiago"));
  

Compilamos el archivo function.ts y ejecutamos el archivo generado function.js:


$ tsc function.ts | node function.js
# Victor Valencia
# Rosa Valencia
# Santiago Valencia
  

Los parámetros obligatorios, opcionales y predeterminados tienen una cosa en común: hablan de un parámetro a la vez. A veces, se requiere trabajar con múltiples parámetros como un grupo, o puede que no sepa cuántos parámetros tomará una función en última instancia. En JavaScript, puede trabajar con los argumentos directamente utilizando la variable de arguments que está visible dentro del cuerpo de cada función.

En TypeScript, puede reunir estos argumentos en una sola variable:


//function.ts
function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}

console.log(buildName("Victor", "Valencia", "Rico"));
console.log(buildName("Joaquín", "Ramirez"));
console.log(buildName("Santiago"));
  

Compilamos el archivo function.ts y ejecutamos el archivo generado function.js:


$ tsc function.ts | node function.js
# Victor Valencia Rico
# Joaquín Ramirez
# Santiago
  

El resto de los parámetros se tratan como un número ilimitado de parámetros opcionales. Al pasarlos de esta manera se puede usar tantos párametros como se desee; incluso puedes pasar ninguno. El compilador construirá una matriz de los argumentos pasados ​​con el nombre dado después de símbolo de puntos suspensivos ..., permitiéndole usarlo en su función.

Angular App Tool: Digitalize polygons
Publicidad
Angular App Tool: Digitalize polygons by Victor Valencia Rico

Clases

JavaScript tradicional utiliza funciones y herencia basada en prototipos para construir componentes reutilizables, pero esto puede resultar un poco incómodo para los programadores más cómodos con un enfoque orientado a objetos, donde las clases heredan la funcionalidad y los objetos se crean a partir de estas clases. A partir de ECMAScript 2015, también conocido como ECMAScript 6, los programadores de JavaScript podrán construir sus aplicaciones utilizando este enfoque basado en clases orientado a objetos. En TypeScript, permite que los desarrolladores usen estas técnicas ahora y las compilen en JavaScript que funcione en todos los principales navegadores y plataformas, sin tener que esperar a la próxima versión de JavaScript.

Veamos un ejemplo simple basado en clases llamado class.ts:


//class.ts
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    console.log("Hello " + this.greeting);
  }
}

let greeter = new Greeter("world");  
greeter.greet();
  

Compilamos el archivo class.ts y ejecutamos el archivo generado class.js:


$ tsc class.ts | node class.js
# Hello world
  

La sintaxis debería resultarle familiar si ha utilizado C# o Java anteriormente. Declaramos una nueva clase Greeter. Esta clase tiene tres miembros: una propiedad llamada greeting, un constructor y un método greet().

Notarás que en la clase cuando nos referimos a uno de los miembros de la clase anteponemos this. Esto denota que es estamos accediendo a una propiedad de la clase.

En las últimas líneas construimos una instancia de la clase Greeter usando new. Esto llama al constructor que definimos anteriormente, creando un nuevo objeto de la clase Greeter y ejecutando el constructor para inicializarlo. Después invocamos el método greet().

Herencia

En TypeScript, podemos usar patrones comunes orientados a objetos. Uno de los patrones más fundamentales en la programación basada en clases es poder extender las clases existentes para crear otras nuevas utilizando la herencia.

Veamos un ejemplo llamado inheritance.ts:


//inheritance.ts
class Animal {
  move(distanceInMeters: number = 0) {
    console.log('Animal moved ' + distanceInMeters + 'm');
  }
}

class Dog extends Animal {
  bark() {
    console.log('Woof! Woof!');
  }
}

const dog = new Dog();
dog.bark();
dog.move(10);
  

Compilamos el archivo inheritance.ts y ejecutamos el archivo generado inheritance.js:


$ tsc inheritance.ts | node inheritance.js
# Woof! Woof!
# Animal moved 10m
  

Este ejemplo muestra la característica de herencia más básica: las clases heredan propiedades y métodos de las clases base. Aquí, Dog es una clase derivada que se deriva de la clase base Animal usando la palabra clave extends. Las clases derivadas a menudo se denominan subclases, y las clases base a menudo se denominan superclases.

Debido a que Dog extiende la funcionalidad de Animal, pudimos crear una instancia de Dog que podía ladrar y moverse; métodos bark() y move() respectivamente.

Veamos ahora un ejemplo más complejo.


//inheritance.ts
class Animal {
  name: string;
  constructor(theName: string) { 
    this.name = theName; 
  }
  move(distanceInMeters: number = 0) {
    console.log(this.name + ' moved ' + distanceInMeters + 'm.');
  }
}

class Snake extends Animal {
  constructor(name: string) { 
    super(name); 
  }
  move(distanceInMeters = 5) {
    console.log("Slithering...");
    super.move(distanceInMeters);
  }
}

class Horse extends Animal {
  constructor(name: string) { 
    super(name); 
  }
  move(distanceInMeters = 45) {
    console.log("Galloping...");
    super.move(distanceInMeters);
  }
}

let cobra = new Snake("Cobra");
let pegaso: Animal = new Horse("Pegaso");

cobra.move();
pegaso.move(34);
  

Compilamos el archivo inheritance.ts y ejecutamos el archivo generado inheritance.js:


$ tsc inheritance.ts | node inheritance.js
# Slithering...
# Cobra moved 5m.
# Galloping...
# Pegaso moved 34m.
  

Este ejemplo cubre algunas otras características que no mencionamos anteriormente. Una vez más, vemos la palabra clave extends utilizada para crear dos nuevas subclases de Animal: Horse y Snake.

Una diferencia con respecto al ejemplo anterior es que cada clase derivada que contiene una función constructora debe llamar a super(), que ejecutará el constructor de la clase base. Además, antes de acceder a una propiedad en su constructor, tenemos que llamar primero a super(). Esta es una regla importante que TypeScript aplicará.

El ejemplo también muestra cómo anular métodos en la clase base con métodos especializados para la subclase. Aquí, Snake y Horse crean un método move() que anula el método move() de Animal, dándole una funcionalidad específica para cada clase. Tenga en cuenta que aunque la variable pegaso se declare como Animal, ya que su tipo es Horse, al llamar a pegaso.move(34) se llamará al método de anulación en Horse.

Wheater Dasboard: Angular + OpenWeather
Publicidad
Wheater Dasboard: Angular + OpenWeather by Victor Valencia Rico

Estructuras iterativas

En TypeScript podemos hacer uso de dos tipos de bucles diferentes for ... in y for ... of

for ... in proviene de versiones antiguas de Javascript, el cual nos permite recorrer objetos iterables obteniendo sus indices.

for ... of es una característica introducida en ECMAScript 6, la cual nos permite recorrer colecciones obteniendo su valor.

Veamos las diferencias con un ejemplo llamado iterators.ts:


//iterators.ts
let list = [1, "string", false];

for (let i in list) {
    console.log(i); // Imprime: 0, 1, 2
}

for (let i of list) {
    console.log(i); // Imprime: 1, string, false
}
  

Compilamos el archivo iterators.ts y ejecutamos el archivo generado iterators.js:


$ tsc iterators.ts | node iterators.js
# 0
# 1
# 2
# 1
# string
# false
  

Módulos

Otra de las características de Typescript es heredada de ECMAScript 6 la posibilidad de crear módulos, los cuales no son más que una forma de encapsular código en su propio ámbito. Nos permiten agrupar nuestro código en diferentes ficheros, permitiéndonos exportarlos y utilizarlos donde los necesitemos. Esto nos facilita la tarea de crear software más ordenado, escalable y mantenible.

Veamos un ejemplo utilizando 2 archivos llamados animal.ts y module.ts:


//animals.ts
export class Animal {
  move(distanceInMeters: number = 0) {
    console.log('Animal moved ' + distanceInMeters + 'm');
  }
}

export class Dog extends Animal {
  bark() {
    console.log('Woof! Woof!');
  }
}

export class Cat extends Animal {
  meow() {
    console.log('Meow! Meow!');
  }
}
  

//module.ts
import { Dog, Cat } from "./animals";
const dog = new Dog();
const cat = new Cat();
dog.move(6); 
dog.bark(); 
cat.move(10);
cat.meow();
  

Compilamos los archivos animal.ts y module.ts, ahora solo ejecutamos el archivo principal module.js:


$ tsc animal.ts module.ts | node module.js
# Animal moved 6m
# Woof! Woof!
# Animal moved 10m
# Meow! Meow!
  

En este ejemplo el archivo llamado animals.ts contiene 3 clases: Animal, como clase base, Dog y Cat como subclases. Además se antepone la palabra reservada export, la cual indica que las clases estarán disponible desde otro archivo que las importe.

Por otr lado, el archivo principal llamado module.ts importa las clases Dog y Cat utilizando la palabra reservada import. Nótese que no es necesario indicar la extensión .ts del archivo importado.

Angular App Tool: Digitalize polygons
Publicidad
Angular App Tool: Digitalize polygons by Victor Valencia Rico

Conclusión

TypeScript incluye muchas características más de las que mencionamos en este tutorial, lo mencionado en este tutorial te ayudará a que comprendan la esencia de TypeScript y el por que ha sobresalido y todo el mundo habla de el. Ademá comentarles que muchos de los frameworks más populares como Angular, React, Vue.js, Nest y próximamente AdonisJS 5 por mencionar algunos, estan basados en TypeScript.

Espero que este tutorial les sirva para comprender los conceptos básicos de Typescript, si ya lo conocías espero que te sirva como referencia y reforces tus conocimientos acerca de TypeScript. Si les ha gustado el tutorial valoren el esfuerzo y compartan en sus redes sociales. No duden en comentar dudas, aportes o sugerencias, estaré encantado de responderles.