Categories
JavaScript TypeScript

Introduction to TypeScript Classes — More 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 more access modifiers for class members in TypeScript.

Readonly modifier

With TypeScript, we can mark a class member as read only with the readonly keyword. This prevents a member from being modified once it’s been initialized. Also, they must be initialized at their declaration or in the constructor. For example, we can use it like in the following code:

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

const person = new Person('Jane');

If we try assign another to it after a value has been set to name after initialization, then we would get an error. For example, if we write:

class Person {  
  readonly name: string;  
  constructor(name: string) {  
    this.name = name;        
  }  
}  
const person = new Person('Jane');  
person.name = 'Joe';

Then the TypeScript compiler won’t compile the code and we would get the error message “Cannot assign to ‘name’ because it is a read-only property.(2540)“

We can make the code above shorter by using parameter properties. With parameter properties, we can both declare a readonly member and assign it a value by just putting the member declaration in the signature of the constructor. Once we put it inside the parentheses, then we can both declare it and assign it a value at the same time. For example, instead of writing:

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

const person = new Person('Jane');

We can instead write:

class Person {    
  constructor(readonly name: string) {      
  }  
}

const person = new Person('Jane');

Then when we run console.log on person , then we can see that the member name has been assigned the value ‘Jane’ without having to explicitly write code to assign it the value. We can also replace readonly , with public , private , or protected ; or combine readonly with public , private , or protected . For example, we can write the following code:

class Person {    
  constructor(private readonly name: string) {      
  } getName() {  
    return this.name;  
  }  
}  
const person = new Person('Jane');  
console.log(person.getName());

to get a private and readonly member called name , which retrieve the value of it in the getName method. We should get ‘Jane’ when we run the console.log line on the last line. Likewise, we can do the same with public or protected like in the following code:

class Person {    
  constructor(protected readonly name: string) {      
  }  
}

class Employee extends Person {    
  constructor(  
    public name: string,   
    private employeeCode: number  
  ){      
    super(name);  
  } 

  getEmployeeCode() {  
    return this.employeeCode;  
  }  
}  
const person = new Employee('Jane', 123);  
console.log(person.name);  
console.log(person.getEmployeeCode());

As we can see, we have parameter properties that with all kinds of access modifiers and the readonly keyword in both the Person and the Employee class. Then we can use the Employee constructor to assign all the values to all the members with the Employee constructor. Then when we get the values of the members either directly or through a method as in the case of the private employeeCode member, where we retrieved it through the getEmployeeCode method, then we can see that the values we expected are logged. We see that person.name is ‘Jane’, and person.getEmployeeCode() gets us 123.

Accessors

Like in JavaScript, we can add getter and setter methods into TypeScript classes. This prevents us from accidentally modifying public member values directly, and gives us more control for how member values are retrieved and set. To add getters and setters to a class, we can use the get and set keywords respectively. We put them in front of the method signature of the class to designate a method as a getter or a setter. For example, we can use it like in the following code:

class Person {  
  private _name: string = ''; get name(): string {  
    return this._name;          
  } 

  set name(newName: string) {  
    if (newName && newName.length < 5) {  
      throw new Error('Name is too short');        
    }  
    this._name = newName;  
  }  
}

let person = new Person();  
person.name = 'Jane Smith';  
console.log(person.name);  
person.name = 'Joe';

In the example above, we added a getter method with the get keyword. The name method is used for getting the _name field, which is private, so we can’t get the value of it without a getter method. To retrieve the value of this._name via our getter name method, we just use the person.name property to get it. Then we to set the value of this._name , we add a setter method with the set keyword and the method name name . In the name setter method, we pass in the parameter which let us assign a value to it with the assignment operator like we did in the third last line in the code above.

As we can see, we can put validation code in the set name method. This is one good reason to use getter and setter methods because we can control how values are set for individual class members. In the example above, if the value we assign has less than 5 characters, then we throw an errors which has the message ‘Name is too short’. This prevents us from assigning a value where the string is less than 5 characters. If we run the code, the first assignment expression:

person.name = 'Jane Smith';

Then we get ‘Jane Smith’ logged. When we try to assign it a value that has less than 5 characters like we did with:

person.name = 'Joe';

Then we get an error raised like we have indicated in the code.

Note that to use accessors, we have to compile our output to ES5 or higher. Compiling to ES3 isn’t supported, but this should be a problems with modern browsers. Also, accessors that has a get but no set are automatically inferred as readonly .

In TypeScript, we have the readonly modifier for class members so that they won’t be able to be set to a new value after they have been initialized. Also, TypeScript has the parameter properties features so that we don’t have to write code explicitly to assign values to variables via the constructor. If we add in the parameters in the constructor, then they’ll be set automatically when we instantiate the class with the new keyword. The accessor methods are useful for controlling how we get and set values of class members. We can designate getter and setter methods with the get and set keywords.

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 *