TypeScript
Las clases
Buscar..
Introducción
TypeScript, como ECMA Script 6, admite la programación orientada a objetos mediante clases. Esto contrasta con las versiones anteriores de JavaScript, que solo son compatibles con la cadena de herencia basada en prototipos.
El soporte de clase en TypeScript es similar al de lenguajes como Java y C #, ya que las clases pueden heredar de otras clases, mientras que los objetos se instancian como instancias de clase.
También similar a esos lenguajes, las clases de TypeScript pueden implementar interfaces o hacer uso de genéricos.
Clase simple
class Car {
public position: number = 0;
private speed: number = 42;
move() {
this.position += this.speed;
}
}
En este ejemplo, declaramos una clase simple de Car
. La clase tiene tres miembros: una speed
propiedad privada, una position
propiedad pública y un move
método público. Tenga en cuenta que cada miembro es público por defecto. Es por eso que move()
es público, incluso si no usamos la palabra clave public
.
var car = new Car(); // create an instance of Car
car.move(); // call a method
console.log(car.position); // access a public property
Herencia básica
class Car {
public position: number = 0;
protected speed: number = 42;
move() {
this.position += this.speed;
}
}
class SelfDrivingCar extends Car {
move() {
// start moving around :-)
super.move();
super.move();
}
}
Este ejemplo muestra cómo crear una subclase muy sencilla del Car
clase utilizando el extends
palabra clave. La clase SelfDrivingCar
anula el método move()
y usa la implementación de la clase base usando super
.
Constructores
En este ejemplo, usamos el constructor
para declarar una position
propiedad pública y una speed
propiedad protegida en la clase base. Estas propiedades se denominan propiedades de parámetros . Nos permiten declarar un parámetro de constructor y un miembro en un solo lugar.
Una de las mejores cosas en TypeScript, es la asignación automática de parámetros del constructor a la propiedad relevante.
class Car {
public position: number;
protected speed: number;
constructor(position: number, speed: number) {
this.position = position;
this.speed = speed;
}
move() {
this.position += this.speed;
}
}
Todo este código se puede resumir en un único constructor:
class Car {
constructor(public position: number, protected speed: number) {}
move() {
this.position += this.speed;
}
}
Y ambos serán transpilados de TypeScript (tiempo de diseño y tiempo de compilación) a JavaScript con el mismo resultado, pero escribiendo mucho menos código:
var Car = (function () {
function Car(position, speed) {
this.position = position;
this.speed = speed;
}
Car.prototype.move = function () {
this.position += this.speed;
};
return Car;
}());
Los constructores de clases derivadas tienen que llamar al constructor de la clase base con super()
.
class SelfDrivingCar extends Car {
constructor(startAutoPilot: boolean) {
super(0, 42);
if (startAutoPilot) {
this.move();
}
}
}
let car = new SelfDrivingCar(true);
console.log(car.position); // access the public property position
Accesorios
En este ejemplo, modificamos el ejemplo de "clase simple" para permitir el acceso a la propiedad de speed
. Los descriptores de acceso de typcript nos permiten agregar código adicional en getters o setters.
class Car {
public position: number = 0;
private _speed: number = 42;
private _MAX_SPEED = 100
move() {
this.position += this._speed;
}
get speed(): number {
return this._speed;
}
set speed(value: number) {
this._speed = Math.min(value, this._MAX_SPEED);
}
}
let car = new Car();
car.speed = 120;
console.log(car.speed); // 100
Clases abstractas
abstract class Machine {
constructor(public manufacturer: string) {
}
// An abstract class can define methods of it's own, or...
summary(): string {
return `${this.manufacturer} makes this machine.`;
}
// Require inheriting classes to implement methods
abstract moreInfo(): string;
}
class Car extends Machine {
constructor(manufacturer: string, public position: number, protected speed: number) {
super(manufacturer);
}
move() {
this.position += this.speed;
}
moreInfo() {
return `This is a car located at ${this.position} and going ${this.speed}mph!`;
}
}
let myCar = new Car("Konda", 10, 70);
myCar.move(); // position is now 80
console.log(myCar.summary()); // prints "Konda makes this machine."
console.log(myCar.moreInfo()); // prints "This is a car located at 80 and going 70mph!"
Las clases abstractas son clases base a partir de las cuales se pueden extender otras clases. No se pueden crear instancias de ellos mismos (es decir, no se puede hacer una new Machine("Konda")
).
Las dos características clave de una clase abstracta en Typescript son:
- Pueden implementar métodos propios.
- Pueden definir métodos que las clases heredadas deben implementar.
Por esta razón, las clases abstractas pueden considerarse conceptualmente como una combinación de una interfaz y una clase .
Monkey parchea una función en una clase existente
A veces es útil poder extender una clase con nuevas funciones. Por ejemplo, supongamos que una cadena se debe convertir en una cadena de caja de camello. Así que debemos decirle a TypeScript que String
contiene una función llamada toCamelCase
, que devuelve una string
.
interface String {
toCamelCase(): string;
}
Ahora podemos parchear esta función en la implementación de String
.
String.prototype.toCamelCase = function() : string {
return this.replace(/[^a-z ]/ig, '')
.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, (match: any, index: number) => {
return +match === 0 ? "" : match[index === 0 ? 'toLowerCase' : 'toUpperCase']();
});
}
Si esta extensión de String
está cargada, se puede usar así:
"This is an example".toCamelCase(); // => "thisIsAnExample"
Transpilacion
Dada una clase SomeClass
, veamos cómo se transpila el TypeScript a JavaScript.
Fuente de TypeScript
class SomeClass {
public static SomeStaticValue: string = "hello";
public someMemberValue: number = 15;
private somePrivateValue: boolean = false;
constructor () {
SomeClass.SomeStaticValue = SomeClass.getGoodbye();
this.someMemberValue = this.getFortyTwo();
this.somePrivateValue = this.getTrue();
}
public static getGoodbye(): string {
return "goodbye!";
}
public getFortyTwo(): number {
return 42;
}
private getTrue(): boolean {
return true;
}
}
Fuente de JavaScript
Cuando se transpila utilizando TypeScript v2.2.2
, la salida es así:
var SomeClass = (function () {
function SomeClass() {
this.someMemberValue = 15;
this.somePrivateValue = false;
SomeClass.SomeStaticValue = SomeClass.getGoodbye();
this.someMemberValue = this.getFortyTwo();
this.somePrivateValue = this.getTrue();
}
SomeClass.getGoodbye = function () {
return "goodbye!";
};
SomeClass.prototype.getFortyTwo = function () {
return 42;
};
SomeClass.prototype.getTrue = function () {
return true;
};
return SomeClass;
}());
SomeClass.SomeStaticValue = "hello";
Observaciones
- La modificación del prototipo de la clase está dentro de un IIFE .
- Las variables miembro se definen dentro de la
function
clase principal. - Las propiedades estáticas se agregan directamente al objeto de clase, mientras que las propiedades de instancia se agregan al prototipo.