TypeScript access modifiers public, private, protected

This blog is a part of my TypeScript series, and the previous ones are:

1. Why program in TypeScript
2. Structural vs nominal typing
3. Getting started with TypeScript classes

TypeScript includes the keywords public, protected, and private to control access to the members of a class i.e. properties or methods.

Class members marked public can be accessed from the internal class methods as well as from the external scripts. This is a default access.

Class members marked as protected can be accessed either from the internal class methods or from its descendants.

The private class members can be accessed from within the class only.

NOTE: If you know languages like Java or C#, you may already know the concept of restricting the access level with private and protected keywords. But TypeScript is a superset of JavaScript, which doesn’t support the private keyword, so the keywords private and protected (as well as public) are removed during the code compilation. The resulting JavaScript won’t include these keywords and you can consider them just as a convenience during development.

The next screenshot illustrates the protected and private access level modifiers. In line 15, the code can access the protected ancestor’s method sayHello(), because its done from the descendant. But when we clicked Ctrl-Space after this. In line 21, the variable age is not shown in the auto–complete list because it’s declared as private and can be accessed only within the class Person.

This code sample shows that the subclass can’t access the private member of the superclass. In general, only a method from the class Person can access private members from this class.

To try this code on your own, visit the TypeScript playground here.

While protected class members are accessible from the descendant’s code, they are not accessible on the class instance. For example, the following code won’t compile and will give you the error “Property ‘sayHello’ is protected and only accessible within class ‘Person’ and its subclasses”:

const empl = new Employee(); +
empl.sayHello(); // error

DISCLAMER: IMO, the protected access level is useless in any programming language. I explained why they are useless in Java back in 2006. Then I continued my witch hunt against seemengly protected creatures in the Adobe Flex framework. As I’m getting older, my motivation to fight protected variables is not as strong as it used to be. Live and let live.

Let’s look at another example of the class Person, which has a constructor, two public and one private property. First, we’ll write a long version of the class declaration.

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

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

The constructor in the class Person performs a tedious job of assigning the values from its argument to the respective members of this class. By using access qualifiers with the constructor’s arguments, you instruct the TypeScript compiler to create class properties having the same names as constructor’s arguments. The compiler will auto-generate the JavaScript code to assign the values given to the constructor to class properties. This will make the code of the TypeScript class more concise as shown in the next screenshot.

TIP: If you’d use just the readonly qualifier with constructor arguments, TypeScript compiler would also create read-only class variables for them.

In line 8, I create an instance of the class Person passing the initial property values to its constructor, which will assign these values to the respective object’s properties. In line 10, I wanted to print the values of the object’s properties firstName and age, but the latter is marked with a red squiggly line. If you hover the mouse over the erroneous fragment, you’ll see that the TypeScript’s static analyzer (it runs even before the compiler) properly reports an error:

Property age is private and only accessible within class Person.

In the TypeScript playground, the JavaScript code is generated anyway because from the JavaScript perspective, the code in line 10 is perfectly fine. But in your projects, you should always use the compiler’s option noEmitOnError to prevent the generation of JavaScript until all TypeScript syntax errors are fixed.

Implementing a singleton with a private constructor

Imagine, you need to create a single place that serves as a storage of important data in memory representing the current state of the app. Various scripts can have an access to this storage but you want to make sure that only one such object can be created for the entire app, also known as a single source of truth.

Singleton is a popular design pattern that restricts the instantiation of a class to only one object. How do you create a class that you can instantiate only once? It’s a rather trivial task in any object-oriented language that supports the private access qualifier.

Basically, you need to write a class that won’t allow using the new keyword, because with the new, you can create as many instances as you want. The idea is simple – if a class has a private constructor, the operator new will fail.

Then, how to create even a single instance of the class? The thing is that if the class constructor is private, you can access if only within the class, and as the author of this class, you’ll responsibly create it only once by invoking that same new operator from the class method.

But can you invoke a method on a class that was not instantiated? Of course, you can! JavaScript (as well as its big brother TypeScript) support static class members, which are shared between multiple instances of the class.

The next listing shows our implementation of the singleton design pattern in a class AppState, which has the property counter. Let’s assume that the counter represents our app state, which may be updated from multiple scripts in the app.

Any of such scripts must update the only place that stores the value of the counter, which is the singleton instance of AppState. Any script that needs to know the latest value of the counter will also get it from the AppState instance.

The class AppState has a private constructor, which means that no other script can instantiate it using the statement new. It’s perfectly fine to invoke such a constructor from within the AppState class, and we do this in the static method getInstance().

The method getInstance() is static, and this is the only way we can invoke a method in the absence of the class instance.

class AppState {

    counter = 0;  
    private static instanceRef: AppState;

    private constructor() { }

    static getInstance(): AppState {
        if (AppState.instanceRef === undefined) {
            AppState.instanceRef = new AppState();
        } 

        return AppState.instanceRef; 
    }
}

// const appState = new AppState(); // error because of the private constructor

const appState1 = AppState.getInstance(); 

const appState2 = AppState.getInstance();

appState1.counter++;
appState1.counter++;
appState2.counter++;
appState2.counter++;

console.log(appState1.counter); // prints 4 
console.log(appState2.counter); // prints 4

Both console.log() invocations will print 4 as there is only one instance of AppState.

To see this code sample in CodePen, visit this page.

7 thoughts on “TypeScript access modifiers public, private, protected

  1. Pingback: TypeScript enums
  2. Great article.
    You didn’t only explain what access modifiers meant, you went on to shed some light on the singleton design pattern.
    Thanks a lot.

Leave a comment