Aprende mecanografiado en 30 minutos

Hoy vamos a echar un vistazo a TypeScript, un lenguaje de compilación a JavaScript diseñado para desarrolladores que crean aplicaciones grandes y complejas. Hereda muchos conceptos de programación de lenguajes como C# y Java que agregan más disciplina y orden al JavaScript, que de otro modo sería muy relajado y de tipo libre.

Este tutorial está dirigido a personas que son bastante competentes en JavaScript pero que aún son principiantes en lo que respecta a TypeScript. Hemos cubierto la mayoría de los conceptos básicos y las funciones clave, al tiempo que incluimos muchos ejemplos con código comentado para ayudarlo a ver el lenguaje en acción. ¡Comencemos!

Los beneficios de usar TypeScript

JavaScript es bastante bueno tal como es y es posible que se pregunte ¿Realmente necesito aprender TypeScript? Técnicamente, no necesita aprender TypeScript para ser un buen desarrollador, la mayoría de las personas lo hacen bien sin él. Sin embargo, trabajar con TypeScript definitivamente tiene sus beneficios:

  • Debido a la tipificación estática, el código escrito en TypeScript es más predecible y, en general, más fácil de depurar.
  • Facilita la organización del código base para aplicaciones muy grandes y complicadas gracias a los módulos, los espacios de nombres y la sólida compatibilidad con programación orientada a objetos.
  • TypeScript tiene un paso de compilación para JavaScript que detecta todo tipo de errores antes de que lleguen al tiempo de ejecución y rompan algo.
  • El próximo marco Angular 2 está escrito en TypeScript y se recomienda que los desarrolladores también usen el lenguaje en sus proyectos.

El último punto es en realidad el más importante para muchas personas y es la razón principal para que usen TypeScript. Angular 2 es uno de los marcos más populares en este momento y, aunque los desarrolladores pueden usar JavaScript normal con él, la mayoría de los tutoriales y ejemplos están escritos en TS. A medida que Angular 2 expande su comunidad, es natural que más y más personas elijan TypeScript.

Instalación de mecanografiado

La forma más sencilla de configurar TypeScript es a través de npm. Usando el siguiente comando podemos instalar el paquete TypeScript globalmente, haciendo que el compilador TS esté disponible en todos nuestros proyectos:

npm install -g typescript

Intenta abrir una terminal en cualquier lugar y ejecutar tsc -v para ver si se ha instalado correctamente.

tsc -v
Version 1.8.10

Editores de texto compatibles con TypeScript

TypeScript es un proyecto de código abierto, pero Microsoft lo desarrolla y mantiene y, como tal, originalmente solo se admitía en la plataforma Visual Studio de Microsoft. Hoy en día, hay muchos más editores de texto e IDE que, ya sea de forma nativa o a través de complementos, ofrecen soporte para la sintaxis de TypeScript, sugerencias de autocompletar, detección de errores e incluso compiladores integrados.

  • Visual Studio Code:el otro editor de código abierto ligero de Microsoft. La compatibilidad con TypeScript está integrada.
  • Complemento gratuito oficial para Sublime Text.
  • La última versión de WebStorm viene con soporte integrado.
  • Más, incluidos Vim, Atom, Emacs y otros.

Compilar en JavaScript

TypeScript está escrito en .ts (o .tsx para JSX), que no se pueden usar directamente en el navegador y deben traducirse primero a vanilla .js. Este proceso de compilación se puede realizar de varias maneras diferentes:

  • En la terminal usando la herramienta de línea de comando mencionada anteriormente tsc .
  • Directamente en Visual Studio o en algunos de los otros IDE y editores de texto.
  • Utilizar ejecutores de tareas automatizados como gulp.

Encontramos que la primera forma es la más fácil y amigable para los principiantes, así que eso es lo que vamos a usar en nuestra lección.

El siguiente comando toma un archivo TypeScript llamado main.ts y lo traduce a su versión JavaScript main.js . Si main.js ya existe, se sobrescribirá.

tsc main.ts

También podemos compilar varios archivos a la vez enumerándolos todos o aplicando comodines:

# Will result in separate .js files: main.js worker.js.
tsc main.ts worker.ts    

# Compiles all .ts files in the current folder. Does NOT work recursively.
tsc *.ts

También podemos usar el --watch opción para compilar automáticamente un archivo TypeScript cuando se realizan cambios:

# Initializes a watcher process that will keep main.js up to date.
tsc main.ts --watch

Los usuarios de TypeScript más avanzados también pueden crear un tsconfig.json archivo, que consta de varias configuraciones de compilación. Un archivo de configuración es muy útil cuando se trabaja en proyectos grandes con muchos archivos .ts, ya que automatiza un poco el proceso. Puede leer más sobre tsconfig.json en los documentos de TypeScript aquí

Escritura estática

Una característica muy distintiva de TypeScript es el soporte de escritura estática. Esto significa que puede declarar los tipos de variables y el compilador se asegurará de que no se les asignen los tipos de valores incorrectos. Si se omiten las declaraciones de tipo, se deducirán automáticamente de su código.

Aquí hay un ejemplo. Cualquier variable, argumento de función o valor devuelto puede tener su tipo definido en la inicialización:

var burger: string = 'hamburger',     // String 
    calories: number = 300,           // Numeric
    tasty: boolean = true;            // Boolean

// Alternatively, you can omit the type declaration:
// var burger = 'hamburger';

// The function expects a string and an integer.
// It doesn't return anything so the type of the function itself is void.

function speak(food: string, energy: number): void {
  console.log("Our " + food + " has " + energy + " calories.");
}

speak(burger, calories);

Debido a que TypeScript está compilado en JavaScript, y este último no tiene idea de qué tipos son, se eliminan por completo:

// JavaScript code from the above TS example.

var burger = 'hamburger',
    calories = 300, 
    tasty = true; 

function speak(food, energy) {
    console.log("Our " + food + " has " + energy + " calories.");
}

speak(burger, calories);

Sin embargo, si intentamos hacer algo ilegal, en la compilación tsc nos avisará que hay un error en nuestro código. Por ejemplo:

// The given type is boolean, the provided value is a string.
var tasty: boolean = "I haven't tried it yet";
main.ts(1,5): error TS2322: Type 'string' is not assignable to type 'boolean'.

También nos avisará si pasamos el argumento equivocado a una función:

function speak(food: string, energy: number): void{
  console.log("Our " + food + " has " + energy + " calories.");
}

// Arguments don't match the function parameters.
speak("tripple cheesburger", "a ton of");
main.ts(5,30): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Estos son algunos de los tipos de datos más utilizados:

  • Número:todos los valores numéricos están representados por el tipo de número, no hay definiciones separadas para enteros, flotantes u otros.
  • Cadena:el tipo de texto, al igual que en las cadenas estándar JS, puede estar entre comillas simples o comillas dobles.
  • Booleano - true o false , usar 0 y 1 provocará un error de compilación.
  • Cualquiera:una variable con este tipo puede tener su valor establecido en una cadena, un número o cualquiera otra cosa.
  • Matrices:tiene dos sintaxis posibles:my_arr: number[]; o my_arr: Array<number> .
  • Vacío:se utiliza en funciones que no devuelven nada.

Para ver una lista de todos los tipos disponibles, vaya a los documentos oficiales de TypeScript, aquí.

Interfaces

Las interfaces se utilizan para verificar si un objeto se ajusta a una determinada estructura. Al definir una interfaz, podemos nombrar una combinación específica de variables, asegurándonos de que siempre irán juntas. Cuando se traducen a JavaScript, las interfaces desaparecen; su único propósito es ayudar en la etapa de desarrollo.

En el siguiente ejemplo, definimos una interfaz simple para verificar los argumentos de una función:

// Here we define our Food interface, its properties, and their types.
interface Food {
    name: string;
    calories: number;
}

// We tell our function to expect an object that fulfills the Food interface. 
// This way we know that the properties we need will always be available.
function speak(food: Food): void{
  console.log("Our " + food.name + " has " + food.calories + " calories.");
}

// We define an object that has all of the properties the Food interface expects.
// Notice that types will be inferred automatically.
var ice_cream = {
  name: "ice cream", 
  calories: 200
}

speak(ice_cream);

El orden de las propiedades NO importa. Solo necesitamos que las propiedades requeridas estén presentes y ser del tipo adecuado . Si falta algo, tiene el tipo incorrecto o tiene un nombre diferente, el compilador nos avisará.

interface Food {
    name: string;
    calories: number;
}

function speak(food: Food): void{
  console.log("Our " + food.name + " has " + food.calories + " grams.");
}

// We've made a deliberate mistake and name is misspelled as nmae.
var ice_cream = {
  nmae: "ice cream", 
  calories: 200
}

speak(ice_cream);
main.ts(16,7): error TS2345: Argument of type '{ nmae: string; calories: number; } 
is not assignable to parameter of type 'Food'. 
Property 'name' is missing in type '{ nmae: string; calories: number; }'.

Esta es una guía para principiantes, por lo que no entraremos en más detalles sobre las interfaces. Sin embargo, hay mucho más en ellos de lo que hemos mencionado aquí, por lo que le recomendamos que consulte los documentos de TypeScript, aquí.

Clases

Al crear aplicaciones a gran escala, muchos desarrolladores prefieren el estilo de programación orientado a objetos, sobre todo en lenguajes como Java o C#. TypeScript ofrece un sistema de clases muy similar al de estos lenguajes, que incluye herencia, clases abstractas, implementaciones de interfaz, setters/getters y más.

También es justo mencionar que desde la actualización de JavaScript más reciente (ECMAScript 2015), las clases son nativas de Vanilla JS y se pueden usar sin TypeScript. Las dos implementaciones son muy similares pero tienen sus diferencias, siendo TypeScript un poco más estricto.

Continuando con el tema de la comida, aquí hay una clase simple de TypeScript:

class Menu {
  // Our properties:
  // By default they are public, but can also be private or protected.
  items: Array<string>;  // The items in the menu, an array of strings.
  pages: number;         // How many pages will the menu be, a number.

  // A straightforward constructor. 
  constructor(item_list: Array<string>, total_pages: number) {
    // The this keyword is mandatory.
    this.items = item_list;    
    this.pages = total_pages;
  }

  // Methods
  list(): void {
    console.log("Our menu for today:");
    for(var i=0; i<this.items.length; i++) {
      console.log(this.items[i]);
    }
  }

} 

// Create a new instance of the Menu class.
var sundayMenu = new Menu(["pancakes","waffles","orange juice"], 1);

// Call the list method.
sundayMenu.list();

Cualquiera que haya escrito al menos un poco de Java o C# debería encontrar esta sintaxis cómodamente familiar. Lo mismo ocurre con la herencia:

class HappyMeal extends Menu {
  // Properties are inherited

  // A new constructor has to be defined.
  constructor(item_list: Array<string>, total_pages: number) {
    // In this case we want the exact same constructor as the parent class (Menu), 
    // To automatically copy it we can call super() - a reference to the parent's constructor.
    super(item_list, total_pages);
  }

  // Just like the properties, methods are inherited from the parent.
  // However, we want to override the list() function so we redefine it.
  list(): void{
    console.log("Our special menu for children:");
    for(var i=0; i<this.items.length; i++) {
      console.log(this.items[i]);
    }

  }
}

// Create a new instance of the HappyMeal class.
var menu_for_children = new HappyMeal(["candy","drink","toy"], 1);

// This time the log message will begin with the special introduction.
menu_for_children.list();

Para obtener una visión más detallada de las clases en TS, puede leer la documentación aquí.

Genéricos

Los genéricos son plantillas que permiten que la misma función acepte argumentos de varios tipos diferentes. Crear componentes reutilizables usando genéricos es mejor que usar el any tipo de datos, ya que los genéricos conservan los tipos de las variables que entran y salen de ellos.

Un ejemplo rápido sería una secuencia de comandos que recibe un argumento y devuelve una matriz que contiene ese mismo argumento.

// The <T> after the function name symbolizes that it's a generic function.
// When we call the function, every instance of T will be replaced with the actual provided type.

// Receives one argument of type T,
// Returns an array of type T.

function genericFunc<T>(argument: T): T[] {    
  var arrayOfT: T[] = [];    // Create empty array of type T.
  arrayOfT.push(argument);   // Push, now arrayOfT = [argument].
  return arrayOfT;
}

var arrayFromString = genericFunc<string>("beep");
console.log(arrayFromString[0]);         // "beep"
console.log(typeof arrayFromString[0])   // String

var arrayFromNumber = genericFunc(42);
console.log(arrayFromNumber[0]);         // 42
console.log(typeof arrayFromNumber[0])   // number

La primera vez que llamamos a la función, configuramos manualmente el tipo en cadena. Esto no es necesario ya que el compilador puede ver qué argumento se ha pasado y decidir automáticamente qué tipo se adapta mejor, como en la segunda llamada. Aunque no es obligatorio, proporcionar el tipo cada vez se considera una buena práctica, ya que el compilador podría fallar en adivinar el tipo correcto en escenarios más complejos.

Los documentos de TypeScript incluyen un par de ejemplos avanzados que incluyen clases genéricas, combinándolas con interfaces y más. Puedes encontrarlos aquí.

Módulos

Otro concepto importante cuando se trabaja en aplicaciones grandes es la modularidad. Tener su código dividido en muchos componentes pequeños reutilizables ayuda a que su proyecto se mantenga organizado y comprensible, en comparación con tener un solo archivo de 10000 líneas para todo.

TypeScript introduce una sintaxis para exportar e importar módulos, pero no puede manejar el cableado real entre archivos. Para habilitar módulos externos, TS se basa en bibliotecas de terceros:require.js para aplicaciones de navegador y CommonJS para Node.js. Echemos un vistazo a un ejemplo simple de módulos de TypeScript con require.js:

Tendremos dos archivos. Uno exporta una función, el otro la importa y la llama.

exportador.ts

var sayHi = function(): void {
    console.log("Hello!");
}

export = sayHi;

importador.ts

import sayHi = require('./exporter');
sayHi();

Ahora necesitamos descargar require.js e incluirlo en una etiqueta de secuencia de comandos; vea cómo aquí. El último paso es compilar nuestros dos archivos .ts. Es necesario agregar un parámetro adicional para indicarle a TypeScript que estamos creando módulos para require.js (también conocido como AMD), a diferencia de los de CommonJS.

tsc --module amd *.ts

Los módulos son bastante complejos y están fuera del alcance de este tutorial. Si desea continuar leyendo sobre ellos, diríjase a los documentos de TS, aquí.

Archivos de declaración de terceros

Cuando usamos una biblioteca que se diseñó originalmente para JavaScript normal, debemos aplicar un archivo de declaración para que esa biblioteca sea compatible con TypeScript. Un archivo de declaración tiene la extensión .d.ts y contiene diversa información sobre la biblioteca y su API.

Los archivos de declaración de TypeScript generalmente se escriben a mano, pero existe una alta probabilidad de que la biblioteca que necesita ya tenga un archivo .d.ts. archivo creado por otra persona. DefinitelyTyped es el repositorio público más grande y contiene archivos de más de mil bibliotecas. También hay un módulo popular de Node.js para administrar definiciones de TypeScript llamado Typings.

Si aún necesita escribir un archivo de declaración usted mismo, esta guía lo ayudará a comenzar.

Próximas funciones en TypeScript 2.0

TypeScript todavía está en desarrollo activo y está evolucionando constantemente. En el momento de escribir este tutorial, la versión LTS es 1.8.10, pero Microsoft ya lanzó una versión Beta para TypeScript 2.0. Está disponible para pruebas públicas y puedes probarlo ahora:

npm install -g [email protected]

Introduce algunos conceptos nuevos útiles como:

  • Indicador de tipos no anulables que evita que algunas variables tengan su valor establecido en null o undefined .
  • Nuevo sistema mejorado para obtener archivos de declaración directamente con un npm install .
  • Análisis de tipo de flujo de control que detecta errores que el compilador no había detectado anteriormente.
  • Algunas innovaciones en la sintaxis de exportación/importación del módulo.

Otra característica largamente esperada es la capacidad de controlar el flujo de funciones asíncronas en un async/await bloquear. Esto debería estar disponible en una futura actualización 2.1.

Lecturas adicionales

La cantidad de información en los documentos oficiales puede ser un poco abrumadora al principio, pero los beneficios de revisarla serán enormes. Nuestro tutorial debe usarse como una introducción, por lo que no hemos cubierto todos los capítulos de la documentación de TypeScript. Estos son algunos de los conceptos más útiles que hemos omitido:

  • Espacios de nombres:aquí.
  • Enumeraciones - aquí.
  • Tipos avanzados y protectores de tipo:aquí.
  • Escribiendo JSX en TypeScript - aquí.

Conclusión

¡Esperamos que hayas disfrutado este tutorial!

¿Tiene alguna idea sobre TypeScript y consideraría usarlo en sus proyectos? ¡Siéntase libre de dejar un comentario a continuación!


No