Skip to content
Aprende a hacer apps móviles con Ionic 2 

Angular2: ¿Aprendo ES6 o TypeScript?

Hace poco un lector me preguntaba ¿Qué es mejor para trabajar con Ionic 2 (o Angular 2): ¿Aprendo ES6 o TypeScript? y sobretodo…¿Por qué debo elegir uno u otro?

La comunidad Angular prefiere TypeScript

Antes de nada decir que en Angular2 se puede trabajar con Javascript “clásico” (ES5), así como ES6 y TypeScript. No obstante Angular2 recomienda utilizar TypeScript y últimamente estamos viendo movimientos en frameworks que utilizan Angular2 (Ionic 2 por ejemplo), así como en developers relevantes dentro de la comunidad, que también abogan por el uso de TypeScript por encima de ES6.

Viendo esta situación, la primera pregunta que se te viene a la cabeza es ¿por qué? ¿qué tiene de especial o mejor TypeScript? ¿porqué debo aprender otro lenguaje en lugar del ESTÁNDAR?

Te recomiendo que leas todo el artículo para entender en detalle los pros y contras, pero si quieres, puedes ir directamente a las conclusiones.

¿Qué es TypeScript?

Para responder a la pregunta anterior, lo primero es entender qué es TypeScript.

TypeScript es un superset de ECMAScript 6, es decir, incluye todas las funcionalidades de ES6, y además incorpora una capa por encima con funcionalidades extra.

Esto, entre otras cosas, significa que tu puedes mezclar código TypeScript con código ES6 estándar sin problema, y el compilador de TypeScript seguirá pasando el código a ES5 (recordemos que tanto ES6 como TypeScript se transpilan a ES5 para que los navegadores actuales puedan ejecutar el código).

TypeScript es un superset de ECMAScript 6, por lo que puedes mezclar TypeScript con ES6 estándar en tu código.

De esto se deriva otra conclusión: La pregunta no debe ser ¿Aprendo ES6 o TypeScript?. Para usar TypeScript hay que saber ES6, por lo que en todo caso, la pregunta es: ¿Aprendo TypeScript?

ES6 deberías aprenderlo sí o sí. La pregunta que te debes hacer es ¿Aprendo también TypeScript?

TypeScript as a JS superset

Diferencias entre ES6 y TypeScript

Variables tipadas

La principal característica de TypeScript por encima de Javascript es que permite definir de qué tipo son las variables que se van a usar.

Veamos un ejemplo. En este caso, voy a crear una clase que tenga una propiedad de tipo array, pero introduciré algún error a propósito.

Versión Javascript:

class MyClass{
    constructor(someArg){
        this.myArray = someArg;
    }
    someMethod(){
        for(let item of this.myArray){
            console.log(item);
        }
    }
}
let someVar = 123456;
let myClassInstance = new MyClass(someVar);
myClassInstance.someMethod();

 
Versión TypeScript:

class MyClass{
  myArray:Array<number>;
    constructor(someArg:string){
        this.myArray = someArg;
    }
    someMethod(){
        for(let item of this.myArray){
            console.log(item);
        }
    }
}
let someVar:number = 123456;
let myClassInstance:MyClass = new MyClass(someVar);
myClassInstance.someMethod();

¿Qué error hay en el ejemplo? -> En ambos casos intento pasar un número a una propiedad que utilizaré más adelante como un array.

¿Resultado?

  • En ES6, no tengo ninguna pista del error, pero fallará en tiempo de ejecución al llamar a someMethod() por que intento utilizar un método de Iterators (el bucle for…of), y la propiedad es un número, que no dispone de dicho método.
  • En TypeScript, en cambio, recibo 2 errores en tiempo de compilación:
    • En primer lugar, me dirá que le estoy intentando asignar un string a un array (primer error que he introducido a propósito en el constructor)
    • En segundo lugar, me dice que no puedo pasar someVar al constructor de MyClass, por que NO es del tipo esperado.

Como vemos, utilizar TypeScript en este ejemplo, ha evitado que me encuentre un error en tiempo de ejecución. Si tengo el plugin adecuado, el mismo editor de código me señalará el error y lo podré arreglar al instante, sin necesidad de ejecutar el código.

TypeScript aporta por tanto mayor robustez, pero en contrapartida hemos tenido que escribir algo más y sobretodo, hemos perdido la flexibilidad de poder pasar lo que queramos en los argumentos.

El uso de variables tipadas de TypeScript aporta mayor robustez al código, pero por contra nos hace perder flexibilidad.

Datos miembro públicos/privados

Un detalle que a veces pasa desapercibido de TypeScript, es que en el constructor podemos declarar directamente los parámetros que recibimos como datos miembro públicos o privados. Es decir, no solo indico si es público o privado, sino que además automáticamente realizo la asignación del parámetro al dato miembro.

En la práctica esto significa que el siguiente código TypeScript:

class HelloWorld {
    constructor(private message: string) {
    }
}

Al compilarse a ES5 se transforma automáticamente en:

class HelloWorld {
    constructor(message: string) {
        this.message = message;
    }
}

Con el beneficio adicional de que si intento acceder al dato miembro message desde fuera de la clase HelloWorld, el compilador de TypeScript me lanzará un error por que lo he definido como privado.

Decorators

La otra característica principal de TypeScript sobre ES6 son los decoradores -y atención, por que estos decoradores están propuestos para ES7, así que probablemente en un futuro formen parte del estandar JS-.

Por si no lo conocías, el patrón de diseño decorador sirve para añadir funcionalidad a un objeto de forma dinámica. Veamos un pequeño ejemplo para entendernos:

const logger = (input) => console.log(input);

const finiteNumbers = (fn) =>
  (item) => {
    if(Number.isFinite(item))
      return fn(item);
  }

[1, "hola", -5, null].map(finiteNumbers(logger)); //1,-5

En el ejemplo, finiteNumbers decora cualquier función que le pasemos como argumento, haciendo que solo se ejecute cuando su valor de entrada sea un número finito.

Como acabamos de ver, nada te impide utilizar este patrón con Javascript tradicional o ES6. Sin embargo lo que acabo de mostrar es un ejemplo muy sencillo, y cuando intentamos aplicar decoradores a clases no estáticas su complejidad aumenta considerablemente.

En cambio, TypeScript proporciona una sintaxis especial para simplificar el uso del patrón decorador. Sin entrar en detalles de como implementarlos, es importante conocer como usarlos, ya que cobran protagonismo en Angular 2.

Los decoradores se pueden utilizar antes de declarar una clase, propiedad, método o parámetro, y utilizan la sintaxis @myDecorator(args)

Veamos un ejemplo con todos ellos:

@SomeClassDecorator(/*some parameters*/)
class MyDecoratedClass {

    @SomePropertyDecorator()
    myDecoratedProperty: string;

    @SomeMethodDecorator()
    myDecoratedMethod(@myParamDecorator() decoratedParam: number) {
    }
}

Entonces… ¿paso del estandar y uso TypeScript?

Tengo que reconocer que al principio opuse cierta resistencia a abandonar ES6 puro y utilizar TypeScript. Lo normal es que te enfrentes a la duda de ¿qué tiene TypeScript que lo haga especial para Angular2?.

Angular 2 utiliza el patrón decorador

Angular 2 utiliza el patrón decorador a lo largo de toda su arquitectura.

Vamos a ver las diferencias mediante un ejemplo. Crearemos un componente básico que recibirá un objeto user y mostrará su propiedad name. La llamada desde el template sería así:

<my-user [user]="selectedUser"></my-user>

Definamos este componente con TypeScript:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'my-user',
  template: '<h1>User {{user.name}}</h1>'
})
export class UserComponent{
    @Input()
    user: User = null;
    constructor(){}
}

Veamos ahora como quedaría la misma definición en ES6:

import {Component} from 'angular@/core';

let componentAnnotation = new Component({
  selector: 'my-user',
  template: '<h1>User {{user.name}}</h1>',
  inputs: ['user']
});
export class UserComponent{
    constructor(){
        this.user = null;
    }
}

UserComponent.annotations = [componentAnnotation];

Podemos ver que en TypeScript usamos 2 decoradores: @Component y @Input. El código queda muy compacto y se entiende fácilmente.

En ES6 tenemos que crear el objeto componente, y añadirlo posteriormente a la clase UserComponent mediante su propiedad annotations. Además, en el componente tenemos que incluir un campo inputs donde pasarle un array de strings con las propiedades que queremos que sean de entrada. Más allá de que podemos caer en errores de escritura, el uso de ES6 puro nos ha llevado a escribir más código.

Desde mi punto de vista, el primer código es mucho más elegante, pero si te resistes a TypeScript, la buena noticia es que tienes un plugin de Babel que te permite utilizar estos decoradores con ES6 y sin necesidad de TypeScript.

Es más sencillo usar Angular 2 con la sintaxis de decorators de TypeScript. Pero también puedes utilizarlos con el plugin transform-decorators-legacy de Babel sin necesidad de recurrir a TypeScript.

Dependency Injection

Angular 2 mantiene el concepto de Inyección de Dependencias que traía AngularJS. Un factor que se criticaba bastante de Angular es que la DI requería de escribir varias veces lo mismo, con el riesgo de cometer algún error.

Veamos un ejemplo de como se soluciona la DI en Angular 2 con ES6:

import {UserService} from './user.service';

export class AnotherService {
  constructor(userService) {
    this.userService = userService;
  }
}
AnotherService.parameters = [[UserService]];

Como vemos, en Angular 2 pasamos los servicios que necesitamos al constructor y se los asignamos como dato miembro. No obstante, necesitamos indicar de algún modo la inyección de dependencias. Esto lo hacemos con la propiedad parameters de la clase.

¿Y qué pasa con TypeScript? Angular 2 se beneficia de los parámetros tipados para inferir la DI. Veamos el código:

import {UserService} from './user.service';

export class AnotherService {
  constructor(private userService:UserService) {}
}

Gracias a que podemos pasar el tipo del servicio en el constructor, Angular 2 detecta que la clase depende de dicho servicio. Además en este ejemplo declaramos directamente userService como una variable privada y no es necesario realizar la asignación dentro del constructor.

Siendo objetivos, esto es de nuevo un punto a favor de TypeScript. Es cierto, también, que si eres reacio a usar TypeScript pero quieres usar este mecanismo para facilitar la DI, el plugin de Babel angular2 annotations es lo que estás buscando.

TypeScript simplifica la Dependency Injection de Angular 2, pero también puedes conseguirlo con el plugin de Babel angular2 annotations.

Analizando los datos con la cabeza fría

TypeScript es ES6 con algunas mejoras que simplifican las cosas al trabajar con Angular 2.

Si eres reticente a abandonar el estándar, es importante destacar que alguna de las mejoras, como lo decoradores, se quiere incluir en ES7, el siguiente estandar de Javascript.

Considerando lo que ofrece TypeScript, usar ES6 puro con Angular 2 es complicarse la vida innecesariamente. Puedes obtener los mismos beneficios que aporta TypeScript con algunos plugins de Babel, pero ¿no es eso, de nuevo, salirse de ES6 puro? Mi consejo ante este dilema… puestos a emular TypeScript, mejor, utiliza TypeScript directamente.

Considerando TypeScript, usar ES6 puro con Angular 2 es complicarse la vida innecesariamente.

Conclusiones

A lo largo de este artículo he desgranado 3 motivos interesantes por los cuales creo que debes considerar TypeScript como primera opción a la hora de trabajar con Angular 2:

  • Detección temprana de errores en fase de compilación
  • Simplificación de código con Decoradores
  • Simplificación de la Inyección de Dependencias

Creo que debes considerar TypeScript como primera opción para Angular 2

Esta es mi opinión personal, pero también es la opinión de mucha gente de peso en el mundo de Angular 2. Recientemente hablaba del tema con Josh Morony – referencia en Ionic 2-, y además de corroborar mi punto de vista, recalcaba la importancia de que la comunidad Angular se está moviendo hacia TypeScript.

¿Y tú, Angulero, qué opinas? ¿Te pasas a TypeScript o prefieres ir a contracorriente?

Published inAngularJSES6JavascriptTypeScript

13 Comments

  1. El mejor artículo que he leído con diferencia. Llevo dos meses leyendo sobre este tema (no solo en español) buscando buenos argumentos y no encontraba nada que me convenciera. En este artículo no solo mencionas los puntos claramente uno por uno y, lo que me parece más importante, para cada uno explicas una alternativa no-Typescript.

    Como algo que se pueda mejorar yo añadiría las Interfaces como punto extra para Typescript, Flow tiene interfaces también pero no son ni la mitad de potentes.

    Muchas gracias, me apunto tu blog a ver que más me encuentro 😉

    • Enrique Oriol Enrique Oriol

      Me alegro de que te guste el enfoque.

      ¡¡Un saludo!!

    • Enrique Oriol Enrique Oriol

      Me alegro de que te guste ¡¡Gracias!!

  2. Hola, muy buen artículo y en español, lo cual es de agradecer. Sin embargo discrepo en un comentario que haces: “Podemos ver que en TypeScript usamos 2 decoradores: @Component y @Input. El código queda muy compacto y se entiende fácilmente.”

    Estoy totalmente de acuerdo que el código es más compacto, pero para nada “se entiende más fácilmente”.
    Con ello, no quiero decir que TypeScript no sea bueno, ni malo, ni mejor ni peor, sino que los decoradores son excesivamente crípticos, y al utilizar una notación tan autocontenida pierdes un poco el control o la noción de lo que se hace.

    Y es que veo que es difícil inferir que este código:

    @Input()
    user: User = null;
    constructor(){}

    sea transpile “aproximadamente” a este:

    inputs: [‘user’]
    });

    constructor(){
    this.user = null;
    }

    Por hacer un simil, la sensación después de ver los decoradores en TS, me recuerda mucho a la sensación que se te quedaba en el cuerpo cuando aprendías la aritmética de punteros en C que tanto les costaba enterder a los programadores nobeles (y no tan nobeles), sobre todo cuando se combinaban punteros de arrays a punteros de funciones con estructuras, etc, etc. LLegaba un momento que veías la notación y perdías bastante tiempo en enterder qué puñetas hacía ese código. Que sí era muy escueto y autocontenido, y permitía hacer cosas fabulosas, pero la notación era endiablada.

    Una de las mayores críticas que recibe AngularJS es que está sobre-ingenierado, o como se diga ese palabro ;), y con Angular 2 en ocasiones parece que han hecho “A” al cuadrado. Por otro lado, alternativas como Aurelia según he leído son más “programmer friendly”, casualmente Rob Eisenberg se salió del proyecto de Angular 2 por discrepancias sobre cómo se pretendían hacer las cosas, y desarrolló paralelamente Aurelia.

    Angular 2 será el motor que haga despegar TypeScript como base para el desarrollo, y son inegables las ventajas de TS, pero de ahí a decir que “se entiende más fácilmente”, va un trecho.

    😉

    • Enrique Oriol Enrique Oriol

      Hola Juan,

      Es cierto que el decorador puede esconder mucha magia detrás, pero no creo que entender la transpilación final sea el objetivo. De lo que se trata es de trabajar a alto nivel (del mismo modo que no te preocupas en mirar como se traducen los lenguajes de hoy en día a ensamblador) y en ese sentido es mucho más inteligible. El código que comentas es el ejemplo perfecto. Fíjate:


      @Input()
      user: User = null;
      constructor(){}

      Con este fragmento se entiende de primeras que user es un input. Y me parece también bastante claro que su valor por defecto es null (además de que es del tipo User).

      En cambio, veamos la equivalencia ES5 que comentabas:



      inputs: [‘user’]
      });

      constructor(){
      this.user = null;
      }

      La parte del constructor es clarísima, pero la propiedad “inputs” a la que le pasas un array de strings, donde los nombres de los strings coinciden con datos miembro… bufff a mi me chirría bastante, sinceramente me parece poco intuitivo, pero es fruto de las limitaciones de ES5.

      Que conste que estoy a favor de los estándares, pero Angular 2 es más fácil de usar de la mano de TS y lo cierto es que TS va muy alineado con la evolución prevista de javascript (los decoradores se proponían para el estándar ECMAScript2016 sin ir más lejos). Que se acaben aceptando “de facto” en JS sin necesidad de transpilar es cuestión de tiempo.

  3. Cristian Cristian

    Excelente analisis, me has convencido al 100%. Aprendere y usare typeScript. Gracias por compartir tus conocimientos y seguire tu blog.

    • Enrique Oriol Enrique Oriol

      ¡Gracias a ti!

  4. oduber vasquez oduber vasquez

    buen día!! una vez más te felicito por compartir tus conocimientos!!! me gustaría saber cómo utilizar django rest_frameword y angular 2!! te agradezco si puedes publicar algunas guías o inducción sobre ese tema

    • Enrique Oriol Enrique Oriol

      Bueno, no tiene ningún misterio, está todo ya publicado. Con Django rest framework montas una API REST y con angular 2 haces peticiones a la API con el servicio Http.

      Si lo que necesitas es algo mucho más guiado, te recomiendo el curso de Ionic 2, donde verás como acceder a recursos REST desde Angular 2 (Ionic 2).

  5. Pedro Pedro

    si aprendo typescript , es necesario aprender javascript ?

    • Enrique Oriol Enrique Oriol

      Hola Pedro,

      Typescript es un superset de Javascript, así que aprender Javascript forma parte del proceso de aprender Typescript. Para decirlo de un modo más informal: cuando usas Typescript, estás usando Javascript con una serie de añadidos. De una forma u otra (por separado o a través de Typescript) tendrás que aprender Javascript.

Deja un comentario