Private, Public & Protected are the Access Modifiers that we can use in Typescript to control whether certain methods or properties are visible to code outside the class. In this tutorial, let us learn about the similarities and differences between them.
Table of Contents
Public
Public access modifier allows the class properties and method freely accessible anywhere in the code. The public is the default access modifier if we do not specify the access modifier
In this example, the Person class has two properties firstName
& lastName
. It also contains a method getName
. All of them are prefixed with the keyword public
. As you can see we can access all of these properties outside the class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class Person { public firstName:string; public lastName:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } getName() : string { return this.firstName + " "+ this.lastName } } let p= new Person("Jon","Snow") console.log(p.firstName) //Jon console.log(p.lastName) //Snow console.log(p.getName()) //Jon Snow |
The above code works even if we remove the keyword public
. Because it is the default access modifier.
Private
The Private access modifier restricts access to the class member from within the class only. We cannot access the property or the method from outside the class
In this example, we mark both firstName & lastName as Private. When we try to access them outside the class we get the compiler error Property 'firstName' is private and only accessible within class
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class Person { private firstName:string; private lastName:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } getName() : string { return this.firstName + " "+ this.lastName } } let p= new Person("Jon","Snow") //Compiler Error console.log(p.firstName) //Property 'firstName' is private and only accessible within class 'Person'. console.log(p.lastName) //Property 'lastName' is private and only accessible within class 'Person' //ok console.log(p.getName()) //Jon Snow |
We cannot even access the private property in a derived class. In this example, the Employee
class extends the Person
class. The changeName
method of the Employee
class tries to access the firstName
& lastName
of the Person
class. The compiler throws the Property is private and only accessible within class 'Person'
error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | class Person { private firstName:string; private lastName:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } getName() : string { return this.firstName + " "+ this.lastName } } class Employee extends Person { designation:string; constructor(firstName:string, lastName:string, designation:string) { super(firstName,lastName) this.designation=designation; } changeName(firstName:string, lastName:string): void { //ERROR this.firstName=firstName; //Property 'firstName' is private and only accessible within class 'Person'. this.lastName=lastName; //Property 'lastName' is private and only accessible within class 'Person'. } } let p= new Employee("Jon","Snow","Manager") //Compiler Error console.log(p.firstName) //Property 'firstName' is private and only accessible within class 'Person'. console.log(p.lastName) //Property 'lastName' is private and only accessible within class 'Person' //ok console.log(p.getName()) //Jon Snow |
Protected
The Protected modifier allows access to the class member from itself and from any classes that inherit (sub-class) from it.
In this example, we have marked the firstName
& lastName
as Protected. We are able to modify these properties in the changeName
method of the derived class Employee.
But accessing these members in the instance created using the Person
class or using the Employee
class results in a compiler error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | class Person { protected firstName:string; protected lastName:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } getName() : string { return this.firstName + " "+ this.lastName } } class Employee extends Person { designation:string; constructor(firstName:string, lastName:string, designation:string) { super(firstName,lastName) this.designation=designation; } changeName(firstName:string, lastName:string): void { //Ok this.firstName=firstName; this.lastName=lastName; } } let p= new Employee("Jon","Snow","Manager") //Compiler Error console.log(p.firstName) //Property 'firstName' is private and only accessible within class 'Person'. console.log(p.lastName) //Property 'lastName' is private and only accessible within class 'Person' //ok console.log(p.getName()) //Jon Snow let p1= new Person("Jon","Snow") //Compiler Error console.log(p.firstName) //Property 'firstName' is private and only accessible within class 'Person'. console.log(p.lastName) //Property 'lastName' is private and only accessible within class 'Person' |
Overriding Access Modifier in the Derived Class
The derived class can redeclare the property and override the Access modifier. In the example, the derived class Employee re-declares the protected
property firstName
& lastName
. This effectively removes the protected
protection from the objects created using the Employee
class. But the objects created using the Person
class will not be able to access the firstName
& lastName
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | class Person { protected firstName:string; protected lastName:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } getName() : string { return this.firstName + " "+ this.lastName } } class Employee extends Person { firstName:string; lastName:string; designation:string; constructor(firstName:string, lastName:string, designation:string) { super(firstName,lastName) this.firstName=firstName; this.lastName=lastName; this.designation=designation; } changeName(firstName:string, lastName:string): void { this.firstName=firstName; this.lastName=lastName; } } //Created from the Employee Class let e= new Employee("Jon","Snow","Manager") //Ok console.log(e.firstName) console.log(e.lastName) //Created from the Person class let p= new Person("Jon","Snow") //Error console.log(p.firstName) //Property 'firstName' is protected and only accessible within class 'Person' and its subclasses. console.log(p.lastName) //Property 'lastName' is protected and only accessible within class 'Person' and its subclasses. |
Readonly Vs Public, Private & Protected
The ReadOnly keyword makes the property read-only. That is you can only initialize it either when you declare it or inside the constructor function. Assigning any value to the readonly property anywhere else results in an error. But it does not prevent you from accessing it. It only prevents you from assigning a value.
Private & Protected prevents you from accessing the variable itself.
We can mix and match both. In this example we mark firstName
& lastName
as both protected and read-only. We can access the property in the changeName
method the derived class Employee
. But we cannot modify it because it is protected.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | class Person { protected readonly firstName:string; protected readonly lastName:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } getName() : string { return this.firstName + " "+ this.lastName } } class Employee extends Person { designation:string; constructor(firstName:string, lastName:string, designation:string) { super(firstName,lastName) this.designation=designation; } changeName(firstName:string, lastName:string): void { //You cann access the property console.log(this.firstName) console.log(this.lastName) //Error Property is readonly. You cannot modify it this.firstName=firstName; //Cannot assign to 'firstName' because it is a read-only property. this.lastName=lastName; //Cannot assign to 'lastName' because it is a read-only property. } } let p= new Employee("Jon","Snow","Manager") //Compiler Error. Cannot access becuase it is protected console.log(p.firstName) //Property 'firstName' is private and only accessible within class 'Person'. console.log(p.lastName) //Property 'lastName' is private and only accessible within class 'Person' |
Optional Property
You can also make the property Optional along with the access modifier and readonly keyword.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Person { protected firstName?:string; protected readonly lastName?:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } getName() : string { return this.firstName + " "+ this.lastName } } |