The private in TypeScript is kinda private

TypeScript includes the keywords public, protected, and private to control access to the members of a class such as properties or methods. Public class members are visible from within and outside the class, protected are visible form the class and its descendents, and private are visible from within the class only. But being a superset of JavaScript, which doesn’t support the private keyword, using private members in TypeScript is not what you may expect.

Let’s look at the example of the class Person, which has three public and one private property.

class Person {
    public firstName: string;
    public lastName: string;
    public age: number;
    private ssn: string;

    constructor(firstName:string, lastName: string, age: number, ssn: string) {
        this.firstName = firstName;
        this.lastName;
        this.age = age;
        this.ssn = ssn;
    }
}

var p = new Person("John", "Smith", 29, "123-90-4567");

console.log("Last name: " + p.lastName + " SSN: " + p.ssn);

The TypeScript compiler properly reports an error at the last line where I tried to access the private variable ssn. Here’s the error:

“Error:(17, 53) TS2341: Property ‘ssn’ is private and only accessible within class ‘Person’.”

But this should have been marked as a warning, because the TypeScript compiler generates the JavaScript code anyway, which looks like this:

var Person = (function () {
    function Person(firstName, lastName, age, ssn) {
        this.firstName = firstName;
        this.lastName;
        this.age = age;
        this.ssn = ssn;
    }
    return Person;
})();

var p = new Person("John", "Smith", 29, "123-90-4567");
console.log("Last name: " + p.lastName + " SSN: " + p.ssn);

To see the code generation in action, visit the TypeScript Playground at http://bit.ly/1GKUeV0. As you see all traces of privacy have been removed, the property ssn has been exposed to the outside world as every other Property on the Person object. There must be some reason why creators of the TypeScript compiler didn’t turn the class Person into the JavaScript closure that would actually make ssn private, for example:

var Person = (function () {
    var _ssn;
    
    function Person(firstName, lastName, age, ssn) {
      
        this.firstName = firstName;
        this.lastName;
        this.age = age;
        _ssn = ssn;
    }
    return Person;
})();

But it is what it is. So when you use the private keyword in TypeScript, keep in mind that it just suggests you to be nice and not access it directly, but write public getter and setter methods instead.

Let’s extend the class Person like this:

class Employee extends Person{
    ssn: number;
}

TypeScript’s compiler will give you an error:

Error:(17, 53) TS2341: Property ‘ssn’ is private and only accessible within class ‘Person’.

But it’ll still generate the JavaScript code unless you add a compiler option –noEmitOnError to not generate JavaScript until all TypeScript syntax errors are fixed. Also, to ensure that the directory with generated JavaScript files doesn’t have files from previous compilation use the build automation tool like Gulp or Grunt with a clean task to remove old generated files on each compile.

Having said that, I still like TypeScript. Developing in TypeScript is clearly more productive than in JavaScript.

P.S. IMO, protected variables are useless in any object–oriented language.

Advertisements

8 thoughts on “The private in TypeScript is kinda private

  1. I don’t understand why “ssn:number” in the class that extends Person gives you an error. Shouldn’t it be possible to have two “ssn”s, one inherited from the base class, and the other one declared in Employee? I understand you can’t access the one from the base class, if it’s private, but shouldn’t the “ssn” from Employee be accessible?

    1. It’s shows the same error in WebStorm as well, but it compiles it anyway into JavaScript. You can save this code in a ts file and compile it with tsc on the command line. You’ll get the error message, but the .js file will be generated anyway.

      1. Just tried again, here is the results:
        Command line: shows error, but anyway compiles to js.
        Visual Studio: shows error and didn’t compile to js, another files in solution also is not compiling until all build errors are fixed.

        Hm, just tried to compile it with command line using flag “–noEmitOnError” and it didn’t compile! For example: “tsc –noEmitOnError app.ts”.
        Looks like Visual Studio uses this flag by default.

  2. I love your P.S. – have the same feeling. Especially in TS using private attributes is kind of awkward for the reason you explained above and also because it makes inheritance a big pain (constructors with different param names for example).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s