Szukaj…


Wprowadzenie

TypeScript, podobnie jak ECMA Script 6, obsługuje programowanie obiektowe za pomocą klas. Kontrastuje to ze starszymi wersjami JavaScript, które wspierały tylko prototypowy łańcuch dziedziczenia.

Obsługa klas w TypeScript jest podobna do obsługi języków takich jak Java i C #, ponieważ klasy mogą dziedziczyć z innych klas, podczas gdy obiekty są tworzone jako instancje klas.

Podobnie do tych języków, klasy TypeScript mogą implementować interfejsy lub korzystać z ogólnych.

Prosta klasa

class Car {
    public position: number = 0;
    private speed: number = 42;
    
    move() {
        this.position += this.speed;
    }
}    

W tym przykładzie deklarujemy prosty Car klasy. Klasa ma trzech członków: speed własności prywatnej, position własności publicznej i move metody publicznej. Pamiętaj, że każdy członek jest domyślnie publiczny. Dlatego move() jest publiczny, nawet jeśli nie użyliśmy public słowa kluczowego.

var car = new Car();        // create an instance of Car
car.move();                 // call a method
console.log(car.position);  // access a public property

Podstawowe dziedziczenie

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();
    }
}

Ten przykład pokazuje, jak utworzyć bardzo prostą podklasę klasy Car za pomocą słowa kluczowego extends . Klasa SelfDrivingCar przesłania metodę move() i używa implementacji klasy podstawowej za pomocą super .

Konstruktory

W tym przykładzie używamy constructor aby zadeklarować position własności publicznej i speed właściwości chronionej w klasie podstawowej. Te właściwości nazywane są właściwościami parametrów . Pozwalają nam zadeklarować parametr konstruktora i członka w jednym miejscu.

Jedną z najlepszych rzeczy w TypeScript jest automatyczne przypisywanie parametrów konstruktora do odpowiedniej właściwości.

class Car {
    public position: number;        
    protected speed: number;

    constructor(position: number, speed: number) {
        this.position = position;
        this.speed = speed;
    }
    
    move() {
        this.position += this.speed;
    }        
}

Cały ten kod można wznowić w jednym konstruktorze:

class Car {
    constructor(public position: number, protected speed: number) {}
    
    move() {
        this.position += this.speed;
    }        
}

Oba zostaną przetransponowane z TypeScript (czas projektowania i czas kompilacji) na JavaScript z tym samym wynikiem, ale pisząc znacznie mniej kodu:

var Car = (function () {
    function Car(position, speed) {
        this.position = position;
        this.speed = speed;
    }
    Car.prototype.move = function () {
        this.position += this.speed;
    };
    return Car;
}());

Konstruktory klas pochodnych muszą wywoływać konstruktor klasy podstawowej za pomocą 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

Akcesoria

W tym przykładzie zmodyfikujemy przykład „Klasa prosta”, aby umożliwić dostęp do właściwości speed . Akcesorium maszynopisu pozwala nam dodawać dodatkowy kod do programów pobierających lub ustawiających.

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

Klasy abstrakcyjne

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!"

Klasy abstrakcyjne to klasy podstawowe, od których mogą się rozciągać inne klasy. Nie można ich utworzyć samodzielnie (tzn. Nie można zrobić new Machine("Konda") ).

Dwie kluczowe cechy abstrakcyjnej klasy w Typescript to:

  1. Mogą wdrażać własne metody.
  2. Mogą definiować metody, które muszą implementować dziedziczące klasy.

Z tego powodu klasy abstrakcyjne można koncepcyjnie uznać za połączenie interfejsu i klasy .

Monkey łata funkcję do istniejącej klasy

Czasami przydaje się możliwość rozszerzenia klasy o nowe funkcje. Załóżmy na przykład, że łańcuch powinien zostać przekształcony w łańcuch wielkości wielbłąda. Musimy więc powiedzieć TypeScript, że String zawiera funkcję o nazwie toCamelCase , która zwraca string .

interface String {
    toCamelCase(): string;
}

Teraz możemy wstawić tę funkcję do implementacji 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']();
        });
}

Jeśli to rozszerzenie String jest załadowane, można je wykorzystać w następujący sposób:

"This is an example".toCamelCase();    // => "thisIsAnExample"

Transpilacja

Biorąc pod uwagę klasę SomeClass , zobaczmy, w jaki sposób TypeScript jest transpilowany na JavaScript.

Źródło 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;
    }

}

Źródło JavaScript

Po transpilacji za pomocą TypeScript v2.2.2 dane wyjściowe wyglądają tak:

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";

Spostrzeżenia

  • Modyfikacja prototypu klasy jest zapakowana w IIFE .
  • Zmienne składowe są zdefiniowane w głównej function klasy.
  • Właściwości statyczne są dodawane bezpośrednio do obiektu klasy, podczas gdy właściwości instancji są dodawane do prototypu.


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow