How are modifiers implemented in TypeScript?

1

TypeScript supports all JavaScript features (ECMAScript 6 itself), as well as modifiers such as private , protected and abstract . However, in ES6 there are no such modifiers.

To "emulate" the modifier private you can do something like:

class MyObject {

    constructor(attr, myArray) {
        this._attr = attr;
        this._myArray = myArray;
        Object.freeze(this);
    }

    get attr(){
        return this._attr;
    }

    get myArray(){
        return [].concat(myArray);
    }
}

Now the modifiers protected and abstract I have no idea how to implement something equivalent in pure JavaScript (vanilla). In this way, I'd like to see what solutions are possible to "emulate" such operators.

    
asked by anonymous 08.02.2018 / 04:39

1 answer

1

The TypeScript compiler generates a JS code and can be viewed as it implements. You can do through the web .

class Person {
    protected name: string;
    constructor(name: string) { this.name = name; }
}

class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name);
        this.department = department;
    }

    public getElevatorPitch() {
        return 'Hello, my name is ${this.name} and I work in ${this.department}.';
    }
}

let howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // error

abstract class Department {

    constructor(public name: string) {
    }

    printName(): void {
        console.log("Department name: " + this.name);
    }

    abstract printMeeting(): void; // must be implemented in derived classes
}

class AccountingDepartment extends Department {

    constructor() {
        super("Accounting and Auditing"); // constructors in derived classes must call super()
    }

    printMeeting(): void {
        console.log("The Accounting Department meets each Monday at 10am.");
    }

    generateReports(): void {
        console.log("Generating accounting reports...");
    }
}

let department: Department; // ok to create a reference to an abstract type
department = new Department(); // error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // error: method doesn't exist on declared abstract type

JavaScript

var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Person = /** @class */ (function () {
    function Person(name) {
        this.name = name;
    }
    return Person;
}());
var Employee = /** @class */ (function (_super) {
    __extends(Employee, _super);
    function Employee(name, department) {
        var _this = _super.call(this, name) || this;
        _this.department = department;
        return _this;
    }
    Employee.prototype.getElevatorPitch = function () {
        return "Hello, my name is " + this.name + " and I work in " + this.department + ".";
    };
    return Employee;
}(Person));
var howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // error
var Department = /** @class */ (function () {
    function Department(name) {
        this.name = name;
    }
    Department.prototype.printName = function () {
        console.log("Department name: " + this.name);
    };
    return Department;
}());
var AccountingDepartment = /** @class */ (function (_super) {
    __extends(AccountingDepartment, _super);
    function AccountingDepartment() {
        return _super.call(this, "Accounting and Auditing") || this;
    }
    AccountingDepartment.prototype.printMeeting = function () {
        console.log("The Accounting Department meets each Monday at 10am.");
    };
    AccountingDepartment.prototype.generateReports = function () {
        console.log("Generating accounting reports...");
    };
    return AccountingDepartment;
}(Department));
var department; // ok to create a reference to an abstract type
department = new Department(); // error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // error: method doesn't exist on declared abstract type

So the protected member is actually private, and that's right, except in the extension it gives special access to the base class.

You may be wondering how you can ensure that something is not accessed without permission. Simple, the compiler does not accept code that does this. Then you should ask if you can modify the% s of Employee and access what you should not. Yes, it can, as it is accessing by reflection, is subverting the guarantees of languages by accessing the generated code. Access outside the class can not be done because JS offers this guarantee.

The abstract method is simply not generated, as it is a contract only the TS compiler needs to know that it exists.

    
08.02.2018 / 10:44