Categories
JavaScript TypeScript

Introduction to TypeScript Classes- Access Modifiers

Spread the love

Classes in TypeScript, like JavaScript are a special syntax for its prototypical inheritance model that is a comparable inheritance in class-based object oriented languages. Classes are just special functions added to ES6 that are meant to mimic the class keyword from these other languages. In JavaScript, we can have class declarations and class expressions, because they are just functions. So like all other functions, there are function declarations and function expressions. This is the same with TypeScript. Classes serve as templates to create new objects. TypeScript extends the syntax of classes of JavaScript and then add its own twists to it. In this article, we’ll look at how to define TypeScript classes and how they inherit from each other. In this article, we’ll look at the access modifiers for class members in TypeScript.

Public, private, and protected modifiers

Public

In TypeScript, class member can have access modifiers added to them. This lets us control the access of the members of class by different parts of the program outside of the class that the members are defined in. The default access modifier for class members in TypeScript is public . This means that class member that have no access modifiers will be designated as public members. For example, we can use the public modifier like in the following code:

class Person {  
  public name: string;  
  public constructor(name: string) {  
    this.name = name;  
  } 

  public getName(): string{  
    return this.name;  
  }  
}

const person = new Person('Jane');  
console.log(person.getName());  
console.log(person.name);

In the example above, we designated all the members in our Person class as public so that we can access them outside the Person class. We can call the getName method on the Person instance and also we can get the name field directly from outside the class. The public access modifier on the constructor method is extra because constructor should always be public so we can instantiate the class with it.

Private and Protected

When a member of a class is marked as private , then it can’t be accessed outside of its containing class. Protected members are only available from within sub-classes of the class that has the protected member and the class that has the member and is marked with the keyword protected. For example, if we have a private member in our class in like the following code:

class Person {  
  private name: string;  
  constructor(name: string) {  
    this.name = name;  
  } 

  public getName(): string{  
    return this.name;  
  }  
}

const person = new Person('Jane');  
console.log(person.getName());  
console.log(person.name);

Then we get an error when we try to access it like we did with the member name in the Person class that we have above. If we try to compile and run the code above, the TypeScript compiler will not compile the code and gives the error message “Property ‘name’ is private and only accessible within class ‘Person’.(2341)“ like we expect for private members.

TypeScript compares type by their structure for public members. If the 2 types have the same public members listed, then they’re marked as being compatible by TypeScript. However, for private and protected members, this isn’t the case. For private and protected members, for 2 classes to be considered equal, then both classes must have the same private and protected members from the same origin for them to be considered to be the same type. For example, if we have the following code:

class Person {  
  private name: string;  
  constructor(name: string) {  
    this.name = name;  
  }  
}

class Human {  
  private name: string;  
  constructor(name: string) {  
    this.name = name;  
  }  
}

const human: Human = new Person('Jane');

Then we would get the error “ Type ‘Person’ is not assignable to type ‘Human’. Types have separate declarations of a private property ‘name’.(2322)“. This means that because both the Person and Human have the same private member called name , that they can’t be considered the same type, so we can’t assign an instance of Person to a variable that’s of type Human . This is the same for protected members, so if we have the following code:

class Person {  
  protected name: string;  
  constructor(name: string) {  
    this.name = name;  
  }  
}

class Human {  
  protected name: string;  
  constructor(name: string) {  
    this.name = name;  
  }  
}

const human: Human = new Person('Jane');

We would get the same error. But if we change protected to public like we do in the code below, then it would work:

class Person {  
  public name: string;  
  constructor(name: string) {  
    this.name = name;  
  }  
}

class Human {  
  public name: string;  
  constructor(name: string) {  
    this.name = name;  
  }  
}

const human: Human = new Person('Jane');  
console.log(human.name);

If we run the code above, we’ll see ‘Jane’ logged from the console.log statement on the last line.

If we have private members in our classes, then they must be in the super-class for both classes for both classes to be considered equal. For example, we can write the following code to make the Person and Human class to be considered the same while having a common private member name for each class:

class Animal {  
  private name: string;  
  constructor(name: string) {  
    this.name = name;        
  }  
}

class Person extends Animal{  
  constructor(name: string) {  
    super(name);      
  }  
}

class Human extends Animal{  
  constructor(name: string) {  
    super(name);      
  }  
}

const human: Human = new Person('Jane');  
console.log(human);

In the code above, we have the Animal class that the private name member, and both the Person and Human classes extends the Animal class, so that the Human and Person will be considered equal since they don’t have separate implementations of the private member name , but rather, a common name member in the Animal class instead which they both inherit from. When we run console.log on human in the last line, we would see the Person object being logged.

Likewise, for protected members, we can do the something similar like in the following code:

class Animal {  
  protected name: string;  
  constructor(name: string) {  
    this.name = name;        
  }  
}

class Person extends Animal{  
  constructor(name: string) {  
    super(name);      
  } 

  getName() {  
    return this.name;  
  }  
}

class Human extends Animal{  
  constructor(name: string) {  
    super(name);      
  } 

  getName() {  
    return this.name;  
  }  
}

const human: Human = new Person('Jane');  
console.log(human.getName());

In the code above, we have the protected member name which can be accessed by its sub-classes Human and Person , so we can return the value of the name member with a getName method on each class and the value of the name member in the Animal class. We need this method because protected members are only available from within sub-classes of the class that has the protected member and the class that has the member. If we run the code above, we would get ‘Jane’ from the console.log output from the last line of the code above.

In TypeScript, class members can have access modifiers applied to them. Public is the default access modifier for members if nothing is specified. 2 class are considered equal if they both have the same public members, or that they inherit protected and private members from the same source and have the same public members.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *