Clases en TypeScript

Author
Por Darío Rivera
Publicado el en TypeScript

En TypeScript, una clase es una plantilla para crear objetos que tienen propiedades y métodos comunes. Ya que TypeScript es un superconjunto de JavaScript soporta el uso de las clases agregadas en la especificación ES2015.

La programación orientada a objetos (POO) es un paradigma de programación cuyo objetivo es modelar objetos del mundo real y sus relaciones en componentes denominados clases. Si es to es nuevo para ti, te recomendamos pasar primero por Introducción a la Programación Orientada a Objetos.

Declaración de clase

En TypeScript podemos definir una clase de la misma manera como lo haríamos en JavaScript.

class Point {
  x: number = 0;
  y: number = 0;

  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }
}

Observa que por defecto TypeScript obliga a que se inicializen los atributos de clase. Este comportamiento hace parte del flag --strictPropertyInitialization. Dado el anterior ejemplo podríamos utilizar el operador new y pasar los argumentos en el "constructor".

const pt = new Point(1, 2);
pt.x = 10;

console.log("X: " + pt.x + ', Y: ' + pt.y);

La salida sería la siguiente:

X: 10, Y: 2

Atributos de lectura

Es posible definir atributos que solo sean de lectura. Con esto, sería imposible tratar de hacer una reasignación a un atributo una vez inicializado. Si modificamos el anterior ejemplo podríamos configurar el atributo x para que sea de solo lectura.

readonly x: number = 0;

Una vez se intente cambiar el valor de dicho atributo TypeScript lanzará un error.

Encapsulamiento

El encapsulamiento es un concepto de programación orientada a objetos que se refiere a la idea de ocultar los detalles internos de una clase o objeto y exponer solo lo que es necesario para su uso externo. TypeScript provee al igual que la mayoría de lenguajes de programación los tipos de acceso public, protected y private.

Public

La visibilidad por defecto de un miembro de clase es por defecto public. Esto implica que es posible acceder a este miembro de clase (propiedad o método) desde cualquier parte.

class Point {
  // atributos definidos como "public"
  public x: number = 1;
  public y: number = 1;

  // método definido como "public"
  public scale(n: number): void {
    // acceso a propiedades internas
    this.x *= n;
    this.y *= n;
  }
}
 
const pt = new Point();

// escalar con método de clase
pt.scale(3);

// escalar accediendo directamente a las propiedades
pt.x = 3;
pt.y = 3;

Protected

Los miembros de clase declarados como protected pueden ser solamente accedidos desde la propia clase o desde subclases desde la que fueron declarados.

class Point {
  // atributos definidos como "protected"
  protected x: number = 1;
  protected y: number = 1;

  // método definido como "protected"
  protected scale(n: number): void {
    // acceso a propiedades internas
    this.x *= n;
    this.y *= n;
  }
}

class SubPoint extends Point {
    scale2x(): void {
        // acceso a propiedades protegidas
        this.x *= 2;
        this.y *= 2;
    }
    scale3x(): void {
        // acceso a método protegido
        this.scale(3);
    }
}
 
const pt = new Point();
pt.scale2x();
pt.scale3x();

El siguiente código arrojaría error debido a que estamos accediando a propiedades protegidas desde un lugar no permitido.

const pt = new SubPoint();

// acceso NO PERMITIDO a propiedades protegidas
pt.x = 3;
pt.y = 3;

// acceso NO PERMITIDO a método protegido
pt.scale(3);

Private

Los miembros de clase declarados como private pueden ser solamente accedidos desde la clase en la cual fueron declarados.

class Point {
  // atributos definidos como "private"
  private x: number = 1;
  private y: number = 1;

  // método definido como "private"
  protected scale(n: number): void {
    // acceso a propiedades internas privadas
    this.x *= n;
    this.y *= n;
  }
}

class SubPoint extends Point {
    scale2x(): void {
        // acceso NO PERMITIDO a propiedades protegidas
        this.x *= 2;
        this.y *= 2;
    }
    scale3x(): void {
        // acceso NO PERMITIDO a método protegido
        this.scale(3);
    }
}
 
const pt = new Point();

// acceso NO PERMITIDO a propiedades protegidas
pt.x = 3;
pt.y = 3;

// acceso NO PERMITIDO a método protegido
pt.scale(3);

Métodos

Para crear métodos en las clases solo debemos agregar nuevas funciones después del constructor. Observa también como en el siguiente método utilizamos this para referirnos a la instancia actual de la clase.

class Point {
  x: number = 0;
  y: number = 0;

  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }

  scale(n: number): void {
    this.x *= n;
    this.y *= n;
  }
}

Utilicemos el método anterior para escalar nuestra instancia en 3x.

const pt = new Point(2, 2);
pt.scale(3);

console.log("X: " + pt.x + ', Y: ' + pt.y);

La salida del anterior programa es la siguiente:

X: 6, Y: 6

Getters

Los getters no son más que métodos que pueden acceder a propiedades definidas en una clase. Generalmente se utilizan cuando no se puede acceder directamente a la propiedad o cuando su acceso involucra una lógica adicional.

class Point {
  private x: number = 1;

  getX(): string {
    return 'X:' + this.x;
  }
}
 
const pt = new Point();
console.log(pt.getX());

En este caso la manera de utilizar el getter es así:

const pt = new Point();
console.log(pt.getX());

Si bien podemos codificar getters de la manera tradicional, algunos lenguajes implementan los getters de una manera particular. En TypeScript podemos hacer uso de la palabra reservada get. Reescribamos el anterior ejemplo para hacer uso de este feature de TypeScript.

class Point {
  private _x: number = 1;

  get x(): string {
    return 'X:' + this._x;
  }
}

De esta forma, el acceso al getter es como si se accediera a la propiedad directamente.

const pt = new Point();
console.log(pt.x);

Setters

Los setters no son más que métodos que pueden modificar a propiedades definidas en una clase. Generalmente se utilizan cuando no se puede acceder directamente a la propiedad o cuando su modificación involucra una lógica adicional.

class Point {
  private x: number = 1;

  setX(value: number): void {
    if (value < 0)
      throw new Error('invalid value for X');
    this.x = value;
  }
}

En este caso la manera de utilizar el setter es así:

const pt = new Point();
pt.setX(3);

Si bien podemos codificar setters de la manera tradicional, algunos lenguajes implementan los setters de una manera particular. En TypeScript podemos hacer uso de la palabra reservada set. Reescribamos el anterior ejemplo para hacer uso de este feature de TypeScript.

class Point {
  private _x: number = 1;

  set x(value: number) {
    if (value < 0)
      throw new Error('invalid value for X');
    this._x = value;
  }
}

De esta forma, el acceso al setter es como si modificara la propiedad directamente en la instancia.

const pt = new Point();
pt.x = 3;

Acerca de Darío Rivera

Author

Application Architect at Elentra Corp . Quality developer and passionate learner with 10+ years of experience in web technologies. Creator of EasyHttp , an standard way to consume HTTP Clients.

LinkedIn Twitter Instagram

Sólo aquellos que han alcanzado el éxito saben que siempre estuvo a un paso del momento en que pensaron renunciar.