Typescript Private Class Properties

Typescript supports private properties for classes

Access control in Typescript classes

Many programming languages define its classes’ properties as private by default. To make them accessible from outside the instance, you typically have to mark the relevant properties with the keyword “public”.

The same keyword is also available in Typescript classes, but doesn’t have much of an impact, as properties in Typescript classes are public by default. This constraint is inherited from Javascript, which doesn’t support private properties in classes. Well, until recently.

Private fields in Javascript?

Yes and no. Currently, a working draft for a spec that defines private properties in Javascript classes is in stage 3, which indicates a final definition is plausible, but not yet sure.

The proposed changes in the spec are really simple and only modify the syntax slightly. To mark a property as private, simply prefix it with a hashtag. That’s it!

class User {
  // A prop marked as private.
  #id;
  age;
  
  constructor(age){
    this.age = age;
    // Valid assignment, as we're 
    // within the class.
    this.#id = Math.floor(Math.random() * 1000);
  }
}

// ... Later in the code ...

const user = new User(42);
// Error! Won't work as it's private.
user.#id = 123;

Private fields in Typescript!

The very same syntax applies for private properties in Typescript. Since version 3.8, you can use this feature to better control access to properties and functions for instances as well as static fields. The syntax is the same as in the Javascript example.

One moment please, private static fields?

Yes, you’ve read right: static variables as well as functions can be private as well, which means they can only be called inside of the class’ members. This feature was added with Typescript version 4.3, together with further changes under the hood. According to the documentation for version 4.3, private class members are now truly private at runtime, which indicates this feature has fully matured.

Please note that Typescript supports two different variants of "private" for classes. The commonly known one is with the keyword "private", which keeps the marked fields unaccessible even from derived classes.

The other feature, which is the one I'm showing here and which is new, is the usage of so called "private names". They're the same syntax as for Javascript, as their spec was defined by JS originally. In Typescript, they control the access during runtime.

/**
 * A class that uses already known
 * private props.
 */
class CommonUser {
  // Common 'private' prop in TS.
  private id: number;
  age: number;
  
  constructor(age: number){
    this.age = age;
    this.id = Math.floor(Math.random() * 1000);
  }
}

/**
 * Using the new sytanx for private class names.
 */
class SpecialUser {
  #id: number;
  age: number;
  
  constructor(age: number){
    this.age = age;
    // Valid, we're inside the class.
    this.#id = SpecialUser.#generateId();
  }
  
  static #generateId(){
    return Math.floor(Math.random() * 1000);
  }
  
  #stringifyId(){
    return this.#id.toString();
  }
}

// ... Later in the code ...

// Invalid, call is outside of class 'SpecialUser'.
SpecialUser.#generateId();

const user = new SpecialUser(42);
// And that won't work as well.
user.#stringifyId();

Last words for the last chapter

This article isn’t very long but highlights a great feature Typescript offers now as well as a more general benefit of Typescript itself. For Javascript, private properties are still a draft (albeit in a very late stage), but for Typescript they’re already implemented and shipped, which shows the speed at which this language is evolving!

Suggestions

Related

Addendum

Languages