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:

  1. Possono implementare metodi propri.
  2. 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.


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow