TypeScript
Classi
Ricerca…
introduzione
TypeScript, come ECMA Script 6, supporta la programmazione orientata agli oggetti usando le classi. Ciò contrasta con le versioni JavaScript precedenti, che supportavano solo la catena di ereditarietà basata su prototipi.
Il supporto di classe in TypeScript è simile a quello di linguaggi come Java e C #, in quanto le classi possono ereditare da altre classi, mentre gli oggetti vengono istanziati come istanze di classe.
Anche simili a questi linguaggi, le classi TypeScript possono implementare interfacce o fare uso di generici.
Classe semplice
class Car {
public position: number = 0;
private speed: number = 42;
move() {
this.position += this.speed;
}
}
In questo esempio, dichiariamo una semplice Car
classe. La classe ha tre membri: una speed
proprietà privata, una position
proprietà pubblica e una move
metodo pubblico. Nota che ogni membro è pubblico per impostazione predefinita. Ecco perché move()
è pubblico, anche se non abbiamo usato la parola chiave public
.
var car = new Car(); // create an instance of Car
car.move(); // call a method
console.log(car.position); // access a public property
Eredità di base
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();
}
}
Questo esempio mostra come creare una sottoclasse molto semplice della classe Car
usando la parola chiave extends
. La classe SelfDrivingCar
sovrascrive il metodo move()
e usa l'implementazione della classe base usando super
.
Costruttori
In questo esempio utilizziamo il constructor
per dichiarare una position
proprietà pubblica e una speed
proprietà protetta nella classe base. Queste proprietà sono chiamate proprietà parametro . Ci permettono di dichiarare un parametro costruttore e un membro in un posto.
Una delle cose migliori in TypeScript è l'assegnazione automatica dei parametri del costruttore alla proprietà rilevante.
class Car {
public position: number;
protected speed: number;
constructor(position: number, speed: number) {
this.position = position;
this.speed = speed;
}
move() {
this.position += this.speed;
}
}
Tutto questo codice può essere ripreso in un singolo costruttore:
class Car {
constructor(public position: number, protected speed: number) {}
move() {
this.position += this.speed;
}
}
Ed entrambi verranno traspolati da TypeScript (tempo di progettazione e tempo di compilazione) a JavaScript con lo stesso risultato, ma scrivendo molto meno codice:
var Car = (function () {
function Car(position, speed) {
this.position = position;
this.speed = speed;
}
Car.prototype.move = function () {
this.position += this.speed;
};
return Car;
}());
I costruttori di classi derivate devono chiamare il costruttore della classe 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
di accesso
In questo esempio, modifichiamo l'esempio "Classe semplice" per consentire l'accesso alla proprietà speed
. Gli accessoristi di tipo dattiloscritto ci consentono di aggiungere codice aggiuntivo nei getter o setter.
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
Classi astratte
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!"
Le classi astratte sono classi base da cui possono estendersi altre classi. Non possono essere istanziati essi stessi (cioè non puoi fare una new Machine("Konda")
).
Le due caratteristiche chiave di una classe astratta in Typescript sono:
- Possono implementare metodi propri.
- Possono definire metodi che l'ereditarietà delle classi deve implementare.
Per questo motivo, le classi astratte possono concettualmente essere considerate una combinazione di un'interfaccia e una classe .
Monkey patch una funzione in una classe esistente
A volte è utile essere in grado di estendere una classe con nuove funzioni. Ad esempio supponiamo che una stringa debba essere convertita in una stringa di un caso cammello. Quindi dobbiamo dire a TypeScript che String
contiene una funzione chiamata toCamelCase
, che restituisce una string
.
interface String {
toCamelCase(): string;
}
Ora possiamo applicare questa funzione nell'implementazione 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']();
});
}
Se questa estensione di String
è caricata, è utilizzabile in questo modo:
"This is an example".toCamelCase(); // => "thisIsAnExample"
Transpilation
Data una classe SomeClass
, vediamo come il TypeScript viene trasposto in JavaScript.
Fonte 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;
}
}
Fonte JavaScript
Quando viene transpiled usando TypeScript v2.2.2
, l'output è come questo:
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";
osservazioni
- La modifica del prototipo di classe è racchiusa all'interno di un IIFE .
- Le variabili membro sono definite all'interno della
function
principale della classe. - Le proprietà statiche vengono aggiunte direttamente all'oggetto classe, mentre le proprietà dell'istanza vengono aggiunte al prototipo.