javascripttypescriptclassaccess-modifierstsc

Observations for compiling classes with TypeScript


Before I proceed, I would like to point out that I have asked a few questions already regarding TypeScript, its compiler and what it has and has not been able to achieve throughout its life and roadmap towards version 1.0

This question relates to the use of public and private keywords in TypeScript, and how these relate to compiled JavaScript.

Consider the following TypeScript class:

class Example {
    private messageA: string;
    public messageB: string;

    constructor(message?: string) {
        this.messageA = "private: " + message;
        this.messageB = "public: " + message;
    }

    public showMessageA(): void {
        alert(this.messageA);
    }

    private showMessageB(): void {
        alert(this.messageB);
    }
}

var example = new Example("Hello World");

Now, when I type example. intellisense (TypeScript) tells me that I can access messageB, and showMessageA, because they are both public. However, this behavior (whilst possible) is not evident in the compiled JavaScript.

Here is the JavaScript compilation for my class:

var Example = (function () {
    function Example(message) {
        this.messageA = "private: " + message;
        this.messageB = "public: " + message;
    }
    Example.prototype.showMessageA = function () {
        alert(this.messageA);
    };

    Example.prototype.showMessageB = function () {
        alert(this.messageB);
    };
    return Example;
})();

var example = new Example("Hello World");

Now, if I paste this example into my browser console (I'm using Chrome), I can access messageA, messageB, showMessageA, showMessageB which implies that in JavaScript, all access modifiers are ignored.

Personally, I think this is wrong! JavaScript is capable of modelling access modifiers so it is my belief that TypeScript should follow suit.

Consider the following hand written JavaScript, which models the private and public variables and functions correctly:

var Example = (function() {
    return function Example(message) {
        var messageA = "private: " + message;
        this.messageB = "public: " + message;

        this.showMessageA = function() {
            alert(messageA);
        }

        var showMessageB = function() {
            alert(this.messageB);
        }
    }
})();

var example = new Example("Hello World");

Now, if I paste this example into my browser console, I can only access messageB and showMessageA, which in accordance with what I was trying to achieve with TypeScript is correct.

QUESTIONS

  1. Why does the TypeScript compiler ignore access modifiers when compiling to JavaScript?
  2. Why does TypeScript bind all methods to the prototype, rather than on a per-instance basis?
  3. If there is anything favorable about the way TypeScript compiles classes in comparison to my custom implementation, what is it, and why?

Solution

  • The problem with using a closure to imitate private access is that every instance needs its own copy of each method. This means that every time you create an instance, each method function has to be compiled and space in memory has to be reserved for the new function. That is not ideal, and not what TypeScript is trying to achieve.