Category: 05. Classes and Objects

https://cdn3d.iconscout.com/3d/premium/thumb/virtual-classroom-3d-icon-png-download-12809800.png

  • Duck Typing

    Duck Typing

    The circumstance where an object’s type is decided by its behavior, like methods and attributes, rather than its class is known as “duck typing”.

    The usage of interfaces in TypeScript makes duck typing possible. Where interface means the set of methods and characteristics an object must have to fall under that type are described.

    For example, if an interface defines the function, any object with the method called “myFunc()” may be treated as belonging to a specific kind, regardless of its class.

    Duck typing emphasizes assessing an object’s suitability for a task by considering its methods and attributes instead of its actual type. An interface explains the set of properties and methods an object must have to be considered “duck typed” for a particular purpose.

    Benefits of Duck Typing

    One of duck typing’s main benefits is making code more flexible and reusable. The code works with any object with the required methods and properties rather than just particular types of objects and may be used in various situations without requiring modification. Duck typing also improves code reuse by enabling the interchangeable usage of objects of diverse kinds within a single codebase.

    Exmaples of Duck Typing is TypeScript

    Here is an example of how to use duck typing in TypeScript

    Define an interface that represents the behaviour you want an object to have. For example

    interfaceDuck{quack():void;}

    Create a class that implements the interface. For example

    classMallardDuckimplementsDuck{quack():void{
    
      console.log("Quack!");}}</code></pre>

    Create an instance of the class and use it as the type defined by the interface.

    let duck: Duck =newMallardDuck();
    duck.quack();// Output: "Quack!"

    Create another class that also implements the interface

    classRubberDuckimplementsDuck{quack():void{
    
      console.log("Squeak!");}}</code></pre>

    Use the new class instance as the same type defined by the interface.

    let duck: Duck =newRubberDuck();
    duck.quack();// Output: "Squeak!"

    As you can see, both MallardDuck and RubberDuck classes implement the Duck interface, and the duck variable can be assigned to instances of both classes. The type is determined by the behaviour (methods and properties) defined in the interface rather than the class.

    It's also important to note that in typescript, you can use the typeof keyword to check the type of object in runtime and if the object has the expected method or property.

    Example

    In this example, the Bird and Plane classes implement the Flyable interface, which requires a fly() method. Both "duck types" can be used interchangeably in the goFly() function. The function doesn't care about the actual type of the object passed to it as long as it has a fly() method that can be called.

    interfaceFlyable{fly():void;}classBirdimplementsFlyable{fly():void{
    
      console.log("Bird is flying");}}classPlaneimplementsFlyable{fly():void{
      console.log("Plane is flying");}}functiongoFly(flyable: Flyable){
    flyable.fly();}let bird =newBird();let plane =newPlane();goFly(bird);// Prints "Bird is flying"goFly(plane);// Prints "Plane is flying"

    On compiling, it will generate the following JavaScript code

    var Bird =/** @class */(function(){functionBird(){}
       Bird.prototype.fly=function(){console.log("Bird is flying");};return Bird;}());var Plane =/** @class */(function(){functionPlane(){}
       Plane.prototype.fly=function(){console.log("Plane is flying");};return Plane;}());functiongoFly(flyable){
       flyable.fly();}var bird =newBird();var plane =newPlane();goFly(bird);// Prints "Bird is flying"goFly(plane);// Prints "Plane is flying"

    Output

    The above code will produce the following output

    Bird is flying
    Plane is flying
    

    Example

    Overall, duck typing is a powerful programming concept that allows for greater flexibility and reusability in TypeScript code by allowing objects of different types to be used interchangeably as long as they have the same methods and properties. In this example, the Driveable interface, Car and Truck classes show the same thing.

    interfaceDriveable{drive():void;}classCarimplementsDriveable{drive():void{
    
    console.log("Car is driving");}}classTruckimplementsDriveable{drive():void{
    console.log("Truck is driving");}}functiongoDrive(driveable: Driveable){
    driveable.drive();}let car =newCar();let truck =newTruck();goDrive(car);// Prints "Car is driving"goDrive(truck);// Prints "Truck is driving"

    On compiling, it will generate the following JavaScript code

    var Car =/** @class */(function(){functionCar(){}
    
    Car.prototype.drive=function(){console.log("Car is driving");};return Car;}());var Truck =/** @class */(function(){functionTruck(){}
    Truck.prototype.drive=function(){console.log("Truck is driving");};return Truck;}());functiongoDrive(driveable){
    driveable.drive();}var car =newCar();var truck =newTruck();goDrive(car);// Prints "Car is driving"goDrive(truck);// Prints "Truck is driving"</code></pre>

    Output

    The above code will produce the following output

    Car is driving
    Truck is driving
    

    The main idea behind duck typing is that the code should be written to work with any object with the methods and properties it needs, rather than being written to work with specific objects. This can make the code more flexible and reusable, allowing you to use different types of objects interchangeably without changing the code.

  • Accessors

    Accessors in TypeScript provides a way to access and set the value of the class members using the getter and setter methods. They control how class members are accessed to read or write their values.

    Accessors are useful for achieving encapsulation in TypeScript, which restricts access to class members only to the member functions of the class, preventing unauthorized access via third parties.

    TypeScript supports the followings to access and change class members:

    • getters
    • setters

    Getters in TypeScript

    Getters are used to access the values of class members and manage how these values are accessed outside of the class. They can be created using the ‘get’ keyword.

    Syntax

    You can follow the syntax below to use getters in TypeScript.

    classclass_name{// Define private variable here.// Defining the gettergetgetter_name(): return_type {// Return variable value}}let val = class_name.getter_name;

    In the above syntax, the method_name method is a static method, which can take multiple parameters and return a value.

    To access the value using the getter, we can use the class name followed by a dot followed by the getter method name.

    Example

    In the example below, we have defined the Person class, which contains the ‘Name’ private variable. It also contains the constructor() method which initializes the value of the ‘Name’ variable.

    // Defining the Person classclassPerson{// Defining the private fieldprivate Name:string;// Defining the constructorconstructor(Name:string){this.Name = Name;}// Defining the gettergetSName():string{returnthis.Name;}}// Creating an instance of the Person classconst person =newPerson("John");console.log(person.SName);// Outputs: John

    On compiling, it will generate the following JavaScript code.

    // Defining the Person classclassPerson{// Defining the constructorconstructor(Name){this.Name = Name;}// Defining the gettergetSName(){returnthis.Name;}}// Creating an instance of the Person classconst person =newPerson("John");console.log(person.SName);// Outputs: John

    Output

    John
    

    Example

    In the code below, the Temperature class contains the ‘celsius’ private variable. The constructor() method initializes the value of the ‘celsius’ variable.

    // Define a class Temperature with a property Celsius of type number.classTemperature{private celsius:number;// Define a constructor that initializes the Celsius property.constructor(celsius:number){this.celsius = celsius;}// Define a getter fahrenheit that returns the temperature in Fahrenheit.getfahrenheit():number{return(this.celsius *9/5)+32;}}// Create an instance of the Temperature class with a temperature of 25 degrees Celsius.const temp =newTemperature(25);console.log("The Fahrenheit value is: "+ temp.fahrenheit);// Outputs: 77

    On compiling, it will generate the following JavaScript code.

    // Define a class Temperature with a property Celsius of type number.classTemperature{// Define a constructor that initializes the Celsius property.constructor(celsius){this.celsius = celsius;}// Define a getter fahrenheit that returns the temperature in Fahrenheit.getfahrenheit(){return(this.celsius *9/5)+32;}}// Create an instance of the Temperature class with a temperature of 25 degrees Celsius.const temp =newTemperature(25);console.log("The Fahrenheit value is: "+ temp.fahrenheit);// Outputs: 77

    Output

    The Fahrenheit value is: 77
    

    Setters in TypeScript

    In TypeScript, setters are used to set the value of class members without accessing them outside of the class. They use the ‘set’ keyword to define the setter method.

    Syntax

    You can follow the syntax below to use setters in TypeScript.

    classclass_name{// Define private variable here.// Defining the settersetsetter_name(val: type){// Set variable value}}
    
    class_name.setter_name = val;

    In the above syntax, we have used the ‘set’ keyword followed by ‘setter_name’ to define a setter. It takes only a single value as a parameter and uses it inside the setter method to change the value of any private class variables.

    To use the setter method, you need to use the class name followed by a dot followed by the setter method name and assign a value to it.

    Example

    In the code below, we have defined the TextContainer class, which contains the ‘_content’ private variable to store the text.

    // Define a class with a private property and a getter/setter methodclassTextContainer{// Define a private propertyprivate _content:string='';// Setter methodsetcontent(value:string){this._content = value.trim().toLowerCase();}// Getter methodgetcontent():string{returnthis._content;}}// Create an instance of the class and set the contentconst text =newTextContainer();
    text.content ="  Hello, WORLD!  ";console.log(text.content);// Outputs: hello, world!

    On compiling, it will generate the following JavaScript code.

    // Define a class with a private property and a getter/setter methodclassTextContainer{constructor(){// Define a private propertythis._content ='';}// Setter methodsetcontent(value){this._content = value.trim().toLowerCase();}// Getter methodgetcontent(){returnthis._content;}}// Create an instance of the class and set the contentconst text =newTextContainer();
    text.content ="  Hello, WORLD!  ";console.log(text.content);// Outputs: hello, world!

    Output

    hello, world!
    

    It is very important to use accessors to achieve encapsulation in TypeScript. You can also create multiple getter and setter methods in a single class.

  • Abstract Classes

    Abstraction Classes

    The abstract classes are used to achieve abstraction in TypeScript. The abstract class contains only method declaration but not implementation. We need to implement all abstract methods of the abstract class into the inherited class.

    The abstraction is a way to hide the lower-level code implementation from users and some developers. Furthermore, it is used to show only the required information about the method rather than showing the whole complex implementation of methods.

    Creating Abstract Classes

    We can use the abstract keyword to define the abstract classes or methods. The abstract classes can contain the normal and abstract types of methods. In the abstract class, we need to implement the functional or normal method and only need to declare the abstract method.

    We can inherit the abstract class using any other class, but we need to implement all abstract methods of the abstract class into the inherited class. If we dont want to implement the abstract method into the inherited class, we need to make an inherited class to abstract using the abstract keyword.

    Also, we cant create the object of the abstract class, but we can create the object of the inherited class and use the abstract class methods. The limitation of the abstract class is that we cant implement multiple inheritances using the multiple abstract classes.

    Syntax

    You can follow the syntax below to create and inherit the abstract class to other classes.

    abstract class sample {
       // define variables inside the abstract class,
       // declare the abstract methods or non-abstract method inside the abstract class
       abstract demo(string): void;
    }
    // extend sample class and implement all abstract methods of sample to demo class
    class test extends sample {
       demo(name: string): void {
    
      // code for the demo method
    } }

    Example 1

    In the example below, we have defined the abstract class containing the abstract methods. In the inherited test class, we have implemented the abstract methods of the sample class. Next, we created the object of the test class with 3 arguments and used that called the demo() and save() methods.

    abstract classsample{// define variables inside the abstract class,
       property1: string;constructor(property1: string, property2: number){this.property1 = property1;}// declare the abstract methods
       abstract demo():void;// defining the non-abstract methodssave():void{
    
      console.log("The save method of the abstract class is executed.");}}// extend sample class and implement all abstract methods of sample to demo classclasstestextendssample{
    property2: number;constructor(property1: string, property2: number){super(property1);this.property2 = property2;}demo():void{// code for the demo method
      console.log("The value of the property 3 is "+this.propert2);}}let test_obj =newtest("TutorialsPont",9999);
    test_obj.demo(); test_obj.save();

    We have hidden the implementation of the save() method from the inherited class test in the above example. We allow developers to implement the demo() method as they want but hide the other class information, such as property1, property2, and implementation of the save() method.

    Now, users understand correctly the motive to use the abstract class and how we can use it to hide the information and can reveal only the required information.

    On compiling, the above code will generate the following JavaScript code

    var __extends =(this&&this.__extends)||(function(){varextendStatics=function(d, b){
    
      extendStatics = Object.setPrototypeOf ||({ __proto__:&#91;]}instanceofArray&amp;&amp;function(d, b){ d.__proto__ = b;})||function(d, b){for(var p in b)if(b.hasOwnProperty(p)) d&#91;p]= b&#91;p];};returnextendStatics(d, b);};returnfunction(d, b){extendStatics(d, b);function__(){this.constructor = d;}
    d.prototype = b ===null? Object.create(b):(__.prototype = b.prototype,new__());};})();var sample =/** @class */(function(){functionsample(property1, property2){this.property1 = property1;}// defining the non-abstract methods sample.prototype.save=function(){
      console.log("The save method of the abstract class is executed.");};return sample;}());// extend sample class and implement all abstract methods of sample to demo classvar test =/** @class */(function(_super){__extends(test, _super);functiontest(property1, property2){var _this =_super.call(this, property1)||this;
      _this.property2 = property2;return _this;}
    test.prototype.demo=function(){// code for the demo method
      console.log("The value of the property 3 is "+this.propert2);};return test;}(sample));var test_obj =newtest("TutorialsPont",9999);
    test_obj.demo(); test_obj.save();

    Output

    It will produce the following output

    The value of the property 3 is undefined
    The save method of the abstract class is executed.
    

    Example 2

    In the example below, the class1 is the abstract class, which contains the declaration of the abstract method name method1. The class2 only contains the definition of method2(). It extended class1 but didnt implement the abstract method named method1().

    After that, we defined class3 and inherited it via class2. Also, we have defined the method1 of class inside class3. At last, we created the object of class3 and invoked the method1() and method2().

    // define the abstract class1 containing the abstract method1
    abstract classclass1{
       abstract method1():void;}// Need to create class2 to abstract as we inherited class1 but doesn't defined abstract method1()
    abstract classclass2extendsclass1{method2():void{
    
      console.log("Inside the method 2 of class2.");}}// defining the class3 inherited by the class2classclass3extendsclass2{// Implementation of the method1 of the abstract class1method1():void{
      console.log("Implemented the abstract method name method1 of class1 inside the class3");}}// Crating the object of the class3var object =newclass3();// Invoking the method1 of class1 which is declared in the abstract class1
    object.method1();// Invoking the method2 of class2 object.method2();

    The above example shows us that if we inherit the abstract class by any class and dont want to implement the abstract method into the inherited class, we need to make the inherited class abstract.

    On compiling, above code will generate the following JavaScript code

    var __extends =(this&&this.__extends)||(function(){varextendStatics=function(d, b){
    
      extendStatics = Object.setPrototypeOf ||({ __proto__:&#91;]}instanceofArray&amp;&amp;function(d, b){ d.__proto__ = b;})||function(d, b){for(var p in b)if(b.hasOwnProperty(p)) d&#91;p]= b&#91;p];};returnextendStatics(d, b);};returnfunction(d, b){extendStatics(d, b);function__(){this.constructor = d;}
         d.prototype = b ===null? Object.create(b):(__.prototype = b.prototype,new__());};})();// define the abstract class1 containing the abstract method1var class1 =/** @class */(function(){functionclass1(){}return class1;}());// Need to create class2 to abstract as we inherited class1 but doesn't defined abstract method1()var class2 =/** @class */(function(_super){__extends(class2, _super);functionclass2(){return _super !==null&amp;&amp;_super.apply(this, arguments)||this;}
    class2.prototype.method2=function(){
      console.log("Inside the method 2 of class2.");};return class2;}(class1));// defining the class3 inherited by the class2var class3 =/** @class */(function(_super){__extends(class3, _super);functionclass3(){return _super !==null&amp;&amp;_super.apply(this, arguments)||this;}// Implementation of the method1 of the abstract class1
    class3.prototype.method1=function(){
      console.log("Implemented the abstract method name method1 of class1 inside the class3");};return class3;}(class2));// Crating the object of the class3var object =newclass3();// Invoking the method1 of class1 which is declared in the abstract class1
    object.method1();// Invoking the method2 of class2 object.method2();

    Output

    It will will produce the following output

    Implemented the abstract method name method1 of class1 inside the class3
    Inside the method 2 of class2.
    
  • Static Methods and Properties

    In TypeScript, static properties belong to the class itself, instead of the instances of the class. The static methods and properties can be accessed without using the instance of the classes. This means you do not need to create an object of the class to use these methods and properties.

    There are two types of properties and methods in TypeScript. One is instance properties and methods and another one is static properties and methods. Here, you will learn about static properties and methods.

    Static properties and methods are useful to create utility functions and constants that don’t change across different instances. For example, if you are creating the circle class, and want to define the ‘PI’ property inside the class, you can make it static as it is a constant.

    Static Properties

    We can use the ‘static’ keyword before the property name to define static properties.

    Syntax

    You can follow the syntax below to define the static properties in TypeScript classes.

    classclassName{static property_name: data_type = value;}

    In the above syntax, we have used the ‘static’ keyword before the property name to define the static property.

    To access the static property, we can use the class name followed by a dot followed by the static property name as shown below.

    className.property_name;

    Example

    In the code below, we have created the ‘circle’ class. The class contains the ‘pi’ static property, which has a constant value.

    classCircle{static pi:number=3.14159;// Static property to hold the value of Pi}console.log("The value of the PI is: "+ Circle.pi);

    On compiling, it will generate the following JavaScript code.

    var Circle =/** @class */(function(){functionCircle(){}
    
    Circle.pi =3.14159;// Static property to hold the value of Pireturn Circle;}());console.log("The value of the PI is: "+ Circle.pi);</code></pre>

    Output

    The output of the above generated JavaScript code is as follows −

    The value of the PI is: 3.14159
    

    Example

    In the code below, we have defined the 'student' class. It contains the static property named 'studentCount' to store the total number of students.

    classStudent{static studentCount:number=0;// Static variable to store the count of studentsconstructor(public name:string,public age:number){this.name = name;this.age = age;
    
        Student.studentCount++;// Incrementing the count of students}// Method to display the student detailsdisplay(){console.log(Name: ${this.name}, Age: ${this.age});}}// Creating objects of Student classlet student1 =newStudent('John',20);let student2 =newStudent('Doe',21);// Accessing static variableconsole.log("Total number of registered students is: "+ Student.studentCount);// Output: 2</code></pre>

    On compiling, it will generate the following JavaScript code.

    classStudent{constructor(name, age){this.name = name;this.age = age;this.name = name;this.age = age;
    
        Student.studentCount++;// Incrementing the count of students}// Method to display the student detailsdisplay(){console.log(Name: ${this.name}, Age: ${this.age});}}
    Student.studentCount =0;// Static variable to store the count of students// Creating objects of Student classlet student1 =newStudent('John',20);let student2 =newStudent('Doe',21);// Accessing static variableconsole.log("Total number of registered students is: "+ Student.studentCount);// Output: 2

    Output

    The output of the above generated JavaScript code is as follows −

    Total number of registered students is: 2
    

    Static Methods

    You can use the 'static' keyword before the method name to declare the static method.

    Syntax

    You can follow the syntax below to define the static methods in TypeScript classes.

    classClass_name{staticmethod_name(params){// Code to be executed}}

    In the above syntax, the method_name method is a static method, which can take multiple parameters and return a value.

    You can call the static method by accessing it using the class name as shown in the code below.

    Class_name.method_name();

    Example

    In the code below, the 'square' class contains the 'area()' static method, which gets the value of the square side as a parameter and returns the area of the square.

    classSquare{// Define a static methodstaticarea(side:number){return side * side;// return the area of the square}}// call the static methodlet area = Square.area(5);console.log(Area of the square: ${area});// Output: Area of the square: 25

    On compiling, it will generate the following JavaScript code.

    classSquare{// Define a static methodstaticarea(side){return side * side;// return the area of the square}}// call the static methodlet area = Square.area(5);console.log(Area of the square: ${area});// Output: Area of the square: 25

    Output

    The output of the above generated JavaScript code is as follows −

    Area of the square: 25
    

    Example

    The below example is very similar to the second example covered in this lesson. It has a private static member named 'studentCount' to store the total number of students.

    classStudent{privatestatic studentCount:number=0;// Static variable to store the count of studentsconstructor(public name:string,public age:number){this.name = name;this.age = age;
    
        Student.studentCount++;// Incrementing the count of students}// Method to get the count of studentsstaticgetStudentCount(){return Student.studentCount;}}// Creating objects of Student classlet student1 =newStudent('John',20);let student2 =newStudent('Doe',21);// Accessing static variableconsole.log("Total number of registered students is: "+ Student.getStudentCount());// Output: 2</code></pre>

    On compiling, it will generate the following JavaScript code.

    classStudent{constructor(name, age){this.name = name;this.age = age;this.name = name;this.age = age;
    
        Student.studentCount++;// Incrementing the count of students}// Method to get the count of studentsstaticgetStudentCount(){return Student.studentCount;}}
    Student.studentCount =0;// Static variable to store the count of students// Creating objects of Student classlet student1 =newStudent('John',20);let student2 =newStudent('Doe',21);// Accessing static variableconsole.log("Total number of registered students is: "+ Student.getStudentCount());// Output: 2

    Output

    The output of the above generated JavaScript code is as follows −

    Total number of registered students is: 2
    

    In real-time development, static properties can be used to store values like application version, particular settings, etc. as they remain constant. In short, you can use static properties to store constant values. Furthermore, you can use static methods when the code of the method is not dependent on any instance property.

  • Inheritance

    Inheritance in TypeScript is a concept that allows us to reuse the properties and methods of a single class with other classes. So, it increases the code readability by allowing the reuse of the codes of different classes.

    TypeScript is an object-oriented programming language, and it supports all features of the OOP. Object-oriented programming has four main pillars and inheritance is one of them.

    TypeScript mainly supports two types of inheritance: single-class inheritance and multilevel inheritance. We will explore each of them in this chapter.

    Single Class Inheritance

    In single-class inheritance, one class inherits the properties of another class. The class that inherits the properties of the other class is called the base class or child class. The class whose properties are inherited is called a parent or superclass.

    You can use the ‘extend’ keyword to achieve inheritance in TypeScript.

    Syntax

    You can follow the syntax below to use the single-class inheritance.

    classChildextendsParent{// Define properties and methods for child class}

    In the above syntax, we have used the ‘extends’ keyword between the name of the child and the parent class.

    Example

    In the code below, we have defined the ‘Vehicle’ class which contains the ‘getType()’ method, returning the vehicle type.

    classVehicle{getType(){return"Vehicle";}}// Define a class Car that extends VehicleclassCarextendsVehicle{
    
    carName:string="Innova";getCarName(){returnthis.carName;}}// Create an object of Car classlet car =newCar();console.log(car.getType());// Output: Vehicleconsole.log(car.getCarName());// Output: Innova</code></pre>

    On compiling, it will generate the following JavaScript code.

    classVehicle{getType(){return"Vehicle";}}// Define a class Car that extends VehicleclassCarextendsVehicle{constructor(){super(...arguments);this.carName ="Innova";}getCarName(){returnthis.carName;}}// Create an object of Car classlet car =newCar();console.log(car.getType());// Output: Vehicleconsole.log(car.getCarName());// Output: Innova

    Output

    Vehicle
    Innova
    

    Super Keyword

    The super keyword is used to call the constructor of the Parent class or access and call the method of the Parent class.

    Syntax

    You can follow the syntax below to use the super keyword to call the constructor and methods of the Parent class in the Child class.

    classChildextendsParent{constructor(){super();// To call the constructor of the parent class}super.method_name();// To call method of the parent class}

    In the above syntax, we have used the 'super()' inside the constructor of the child class to call the constructor of the parent class.

    In 'super.method_name()', method_name is the name of the method of the parent class.

    Example

    In the code below, we have defined the Person class which contains the 'name' property, and initialized it inside the constructor() method. The display() method prints the value of the name property.

    classPerson{
    
    name:string;constructor(name:string){this.name = name;}display():void{console.log(this.name);}}// Employee class is inheriting the Person classclassEmployeeextendsPerson{
    empCode:number;constructor(name:string, code:number){super(name);this.empCode = code;}show():void{super.display();}}// Creating the object of Employee classlet emp =newEmployee("Sam",123);
    emp.show();// Sam

    On compiling, it will generate the following JavaScript code.

    classPerson{constructor(name){this.name = name;}display(){console.log(this.name);}}// Employee class is inheriting the Person classclassEmployeeextendsPerson{constructor(name, code){super(name);this.empCode = code;}show(){super.display();}}// Creating the object of Employee classlet emp =newEmployee("Sam",123);
    emp.show();// Sam

    Output

    The above code example will produce the following result -

    Sam
    

    Method Overriding

    The method overriding concept allows you to override the code of the particular method of the parent class inside the child class. This way, you can have a method with the same name in the parent and child classes, having different functionalities.

    Example

    In the code below, the Animal class has a move() method which works for any animal. After that, we have extended the Dog class with the Animal class. The Dog class has its own move() method, and that's how we do method overriding.

    classAnimal{move(){console.log("Animal is moving");}}// Dog class is inheriting Animal classclassDogextendsAnimal{// Method overridingmove(){console.log("Dog is moving");}}let dog =newDog();
    dog.move();// Output: Dog is moving

    On compiling, it will generate the same JavaScript code.

    Output

    The above code example will produce the following result -

    Dog is moving
    

    Multilevel Inheritance

    Multilevel inheritance allows you to inherit the properties of the parent class, where the parent class also inherits the other class.

    Example

    In the code below, the Parrot class inherits the properties and methods of the Bird class, and the Bird class inherits the properties and methods of the Animal class. However, you may have more levels of multilevel inheritance in real-time development.

    classAnimal{// Move methodmove(){console.log('This animal moves');}}// Bird class extends Animal classclassBirdextendsAnimal{// Bird can flyfly(){console.log('This bird flies');}}// Parrot class inherits the Bird classclassParrotextendsBird{// Parrot can speakspeak(){console.log('The parrot speaks');}}// Creating an instance of the Parrot classletP1=newParrot();P1.speak();

    On compiling, it will generate the same JavaScript code.

    Output

    The above code example will produce the following result -

    The parrot speaks
    

    Multiple Inheritance, Hierarchical Inheritance, and Hybrid Inheritance are also supported by some object-oriented programming languages but not supported by TypeScript. You may use the interface or prototype-based inheritance to achieve multiple inheritance.

  • Readonly Properties

    TypeScript provides us with readonly keyword to make a property in class, type or interface as read-only. The readonly properties can be accessed outside the class but their values can’t be modified.

    By using the readonly properties, you can ensure that no one can modify the property outside the object, but they can read the value of the property.

    Syntax

    To define readonly properties in TypeScript, we prefix the property name with the readonly keyword.

    readonly propName: type;

    Where,

    • In the above syntax, ‘readonly’ is a keyword.
    • The ‘propName’ is a property name of the readonly property.
    • The ‘type’ is a property type of the readonly property.

    The encapsulating entity may be a class or an interface in TypeScript.

    You can replace propertyName with the desired name for the readonly property, and type with the appropriate data type.

    The readonly Properties with Interface

    Interface is used to define the prototype of the object. We can define the readonly properties in the interface. Let’s understand it via the example below.

    Example

    In the code below, we have defined the Car interface containing the model, year, and fuel properties. Here, the fuel property is readonly, which can be initialized only while creating the object but can’t be changed after creating the object.

    After that, we have created the object of the Car type and initialized all properties.

    You can try to change the value of the fuel property of the car object, and observe the error.

    //  Defining the interface for the carinterfaceCar{
    
    model:string;
    year:number;readonly fuel:string;}// Defining the car objectlet car: Car ={
    model:'BMW',
    year:2019,
    fuel:'petrol'}console.log(car.model);console.log(car.year);console.log(car.fuel);// Error: Cannot assign to 'fuel' because it is a read-only property.// car.fuel = 'diesel';</code></pre>

    On compiling, it will generate the following JavaScript code.

    // Defining the car objectlet car ={
    
    model:'BMW',
    year:2019,
    fuel:'petrol'};console.log(car.model);console.log(car.year);console.log(car.fuel);// Error: Cannot assign to 'fuel' because it is a read-only property.// car.fuel = 'diesel';</code></pre>

    Output

    The output of the above example code is as follows −

    BMW
    2019
    petrol
    

    The readonly Properties with Classes

    The class can also contain readonly properties similar to the interfaces. The value of the readonly properties can be initialized in the constructor() method while creating the object. You can't change the value of the readonly properties of the class using the class instance.

    Example

    In the code below, we have defined the car class which contains the model and price properties. It also contains the 'type' readonly property.

    In the constructor() method, we initialize the values of all properties including the 'type' readonly property.

    The display() method prints the values of all properties.

    After that, we have created the object of the car class. Now, you can try to change the value of the 'type' property of the car object, it will throw an error as it is readonly.

    // Defining the class for carclassCar{// Properties
    
    model:string;
    price:number;readonly type:string='Car';// Constructorconstructor(model:string, price:number, type:string){this.model = model;this.price = price;this.type = type;}// Methoddisplay():void{console.log(Model: ${this.model}, Price: ${this.price}, Type: ${this.type});}}// Creating object of Car classlet car =newCar('BMW',1000000,'Sedan');
    car.display();// Try to change the value of readonly property// car.type = 'SUV'; // Error: Cannot assign to 'type' because it is a read-only property.

    On compiling, it will generate the following JavaScript code.

    // Defining the class for carclassCar{// Constructorconstructor(model, price, type){this.type ='Car';this.model = model;this.price = price;this.type = type;}// Methoddisplay(){console.log(Model: ${this.model}, Price: ${this.price}, Type: ${this.type});}}// Creating object of Car classlet car =newCar('BMW',1000000,'Sedan');
    car.display();// Try to change the value of readonly property// car.type = 'SUV'; // Error: Cannot assign to 'type' because it is a read-only property.

    Output

    The output of the above code example is as follows −

    Model: BMW, Price: 1000000, Type: Sedan
    

    The readonly Properties with Type Aliases

    Type aliases are used to define a type for the object. It can also contain readonly properties similar to the interface.

    Example

    In the code below, 'Point' is a type alias that contains 'x' and 'y' properties and both are readonly.

    After that, we defined the P1 point of type 'Point' and initialized the values of 'X' and 'Y' properties while defining it.

    Next, try to change the value of any property of the 'P1' point. It will throw an error as both properties of P1 are readonly.

    //  Readonly Properties with type aliastypePoint={readonly x:number;readonly y:number;}let p1: Point ={ x:10, y:20};// p1.x = 5; // Errorconsole.log(p1.x, p1.y);

    On compiling, it will generate the following JavaScript code.

    let p1 ={ x:10, y:20};// p1.x = 5; // Errorconsole.log(p1.x, p1.y);

    Output

    The output is as follows −

    10 20
    

    Const vs. readonly Properties

    The 'const' keyword is similar to the 'readonly' keyword but there are some minor differences.

    • The 'const' keyword is used to declare the constant variables, whereas the 'readonly' keyword is used to declare the readonly properties of objects.
    • You need to assign value to the variable declared using the 'const' keyword while declaring it, but for 'readonly' properties, you can assign values while creating the object.
    • The value of 'const' variables can't be changed after declaring it, and the value of 'readonly' properties can't be changed outside the object or class.

    When to Use Readonly

    • Data Integrity: When you want to ensure that certain properties of an object don't change after their initial assignment.
    • Functional Programming: It helps in programming paradigms where immutability is a cornerstone.
    • API Contracts: When creating objects that are exposed to external users and you need to guarantee that the internal state won't be altered unexpectedly.
  • Access Modifiers

    The concept access modifiers are used to implement encapsulation or data hiding in TypeScript. The access modifiers define the visibility class members outside the defining class. The class members are properties and functions. The access modifiers are also known as access specifiers.

    TypeScript supports three types of access modifiers publicprivate and protected. These modifiers are the keywords that are used to declare a class member as public, private or protected.

    A public class member is accessible from anywhere in the code. A private member is only accessible within the class that defines it. And a protected member is accessible from within the class and derived classes.

    Let’s understand each of the three access modifiers discussed above in details.

    Public Access Modifier

    A public access modifier in TypeScript defines a public class member. By default, a member of class is public. So it’s optional to use public keyword to declare a member public. The public members are accessible from anywhere within and outside the class that defines the member.

    Example

    In the example below, we have created a class named Person. The class Person has two members, one a public property name and other a public method greet(). As these members are declared as public, these can be accessed from anywhere in the program.

    We also created an instance of the Person class as person. We access the name property of the person object and assign a value to it. Finally, we called the greet function to display the greeting with new name.

    classPerson{public name:string="";publicgreet():void{console.log(Hello, my name is ${this.name}!);}}const person =newPerson(); 
    person.name ="John"; 
    person.greet();

    On compiling, it will generate the following JavaScript code.

    classPerson{constructor(){this.name ="";}greet(){console.log(Hello, my name is ${this.name}!);}}const person =newPerson();
    person.name ="John";
    person.greet();

    The output of the above example code is as follows

    Hello, my name is John!
    

    Private Access Modifiers

    A private access modifier restricts the access of the class member (property or method) to the class where it is declared. When you add the private modifier to the property or method, you can access that property or method within the same class only.

    A private access modifier in TypeScript defines a private class member. Private members are accessible from within the class that defines them.

    Example

    In this example, we have created a BankAccount class with a private property balance, which can only be accessed and modified within the class. Additionally, we have a private method calculateInterest(), that calculates the interest based on the balance.

    You can observe in the output that attempting to access the private members will result in a TypeError.

    classBankAccount{private balance:number;constructor(initialBalance:number){this.balance = initialBalance;}privatecalculateInterest():number{const interestRate =0.05;returnthis.balance * interestRate;}}// Creating an instance of the BankAccount classconst account =newBankAccount(1000);// Attempting to access private membersconsole.log(account.balance);console.log(account.calculateInterest());

    On compiling, it will generate the following JavaScript code.

    classBankAccount{constructor(initialBalance){this.balance = initialBalance;}calculateInterest(){const interestRate =0.05;returnthis.balance * interestRate;}}// Creating an instance of the BankAccount classconst account =newBankAccount(1000);// Attempting to access private membersconsole.log(account.balance);console.log(account.calculateInterest());

    And it will give the following error

    Property 'balance' is private and only accessible within class 'BankAccount'.
    Property 'calculateInterest' is private and only accessible within class 'BankAccount'.
    

    The output of the above example code is as follows

    1000
    50
    

    Protected Access Modifiers

    The protected access modifier is used to define a protected class member (property or method). A protected data member is accessible only within the class that defines it or any class that extends it.

    Example

    In this example, we create a base class Animal with a protected property name, which can be accessed and modified within the class and its derived classes. We also have a protected method makeSound(), that simply logs a message.

    We then create a derived class Dog that extends the Animal class. The Dog class adds a public method bark(), which utilizes the name property inherited from the base class to output a bark message.

    Finally, we create an instance of the Dog class named dog with the name “Buddy” and call the bark() method.

    The output will show the dog’s name followed by the bark message.

    classAnimal{protected name:string;constructor(name:string){this.name = name;}protectedmakeSound():void{console.log("The animal makes a sound");}}classDogextendsAnimal{publicbark():void{console.log(${this.name} barks!);}}// Creating an instance of the Dog classconst dog =newDog("Buddy"); 
    dog.bark();

    On compiling, it will generate the following JavaScript code.

    classAnimal{constructor(name){this.name = name;}makeSound(){console.log("The animal makes a sound");}}classDogextendsAnimal{bark(){console.log(${this.name} barks!);}}// Creating an instance of the Dog classconst dog =newDog("Buddy");
    dog.bark();

    The output of the above example code is as follows

    Buddy barks!
    
  • Objects

    An object in TypeScript is an instance which contains set of key value pairs. The key value pairs are also referred as object properties. The values can be scalar values or functions or even array of other objects. If a property’s value is a function, that property is known as method.

    Syntax

    The syntax to create an object in TypeScript is given below

    var object_name ={ 
       key1:"value1",//scalar value 
       key2:"value",key3:function(){//functions }, 
       key4:["content1","content2"]//collection  };

    As shown above, an object can contain scalar values, functions and structures like arrays and tuples.

    Type Annotations

    In TypeScript, we should annotate the object properties as follows

    let person:{name:string, age:number}={
       name:"Tom Hanks",
       age:35,}

    In the above example we annotated the properties name and age of the person object.

    We can also use interface to create type for object properties. Look the below example

    interfacePersonType{
       fullname:string;
       age:number}var person: PersonType ={ fullname:"Tom Hanks", age:32};

    Object Literal Notation

    The object literal notation is the easiest way to create an object in TypeScript. We use curly braces ({}) to create object. Each property of the object is separated by a comma. Each property is written as property name (key) followed by colon (:) followed by property value.

    Example

    In the example below, we have created an object named person containing two properties. The first property is firstname: “Tom” and the second property is lastname: “Hanks”. We access the property values and print them in console.

    var person:{ firstName:string, lastName:string}={ 
       firstName:"Tom", 
       lastName:"Hanks"};//access the object values console.log(person.firstName)console.log(person.lastName)

    On compiling, it will generate the following code in JavaScript.

    var person ={
    
    firstName:"Tom",
    lastName:"Hanks"};//access the object values console.log(person.firstName);console.log(person.lastName);</code></pre>

    Output

    Tom 
    Hanks
    

    TypeScript Type Template

    Let's say you created an object literal in JavaScript as

    var person ={ 
       firstname:"Tom", 
       lastname:"Hanks"};

    In case you want to add some value to an object, JavaScript allows you to make the necessary modification. Suppose we need to add a function to the person object later this is the way you can do this.

    person.sayHello=function(){return"hello";}

    If you use the same code in Typescript the compiler gives an error. This is because in Typescript, concrete objects should have a type template. Objects in Typescript must be an instance of a particular type.

    You can solve this by using a method template in declaration.

    Example: Typescript Type template

    var person ={
       firstName:"Tom", 
       lastName:"Hanks",sayHello:function(){}//Type template } 
    person.sayHello=function(){console.log("hello "+person.firstName)}  
    person.sayHello()

    On compiling, it will generate the same code in JavaScript.

    Output

    The above generated JavaScript code will produce the following output -

    hello Tom
    

    Objects as Function Parameters

    Objects can also be passed as parameters to function.

    Example: Objects as function parameters

    var person ={ 
       firstname:"Tom", 
       lastname:"Hanks"};varinvokeperson=function(obj:{ firstname:string, lastname :string}){console.log("first name :"+obj.firstname)console.log("last name :"+obj.lastname)}invokeperson(person)

    The example declares an object literal. The function expression is invoked passing person object.

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var person ={
       firstname:"Tom",
       lastname:"Hanks"};varinvokeperson=function(obj){console.log("first name :"+ obj.firstname);console.log("last name :"+ obj.lastname);};invokeperson(person);

    Output

    first name :Tom 
    last name :Hanks
    

    Anonymous Objects

    You can create and pass an anonymous object on the fly.

    Example: Anonymous Object

    varinvokeperson=function(obj:{ firstname:string, lastname :string}){console.log("first name :"+obj.firstname)console.log("last name :"+obj.lastname)}invokeperson({firstname:"Sachin",lastname:"Tendulkar"});

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10varinvokeperson=function(obj){console.log("first name :"+ obj.firstname);console.log("last name :"+ obj.lastname);};invokeperson({ firstname:"Sachin", lastname:"Tendulkar"});

    Output

    first name :Sachin 
    last name :Tendulkar
    

    Duck-typing

    In duck-typing, two objects are considered to be of the same type if both share the same set of properties. Duck-typing verifies the presence of certain properties in the objects, rather than their actual type, to check their suitability. The concept is generally explained by the following phrase

    When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.

    The TypeScript compiler implements the duck-typing system that allows object creation on the fly while keeping type safety. The following example shows how we can pass objects that dont explicitly implement an interface but contain all of the required members to a function.

    Example

    interfaceIPoint{ 
       x:number 
       y:number}functionaddPoints(p1:IPoint,p2:IPoint):IPoint {var x = p1.x + p2.x 
       var y = p1.y + p2.y 
       return{x:x, y:y}}//Valid var newPoint =addPoints({x:3,y:4},{x:5,y:1})//Error var newPoint2 =addPoints({x:1},{x:4,y:3})

  • Classes

    TypeScript is object oriented JavaScript. TypeScript supports object-oriented programming features like classes, interfaces, etc. A class in terms of OOP is a blueprint for creating objects. A class encapsulates data for the object. Typescript gives built in support for this concept called class. JavaScript ES5 or earlier didnt support classes. Typescript gets this feature from ES6.

    Creating classes

    Use the class keyword to declare a class in TypeScript. The syntax for the same is given below −

    Syntax

    class class_name { 
       //class scope 
    }
    

    The class keyword is followed by the class name. The rules for identifiers must be considered while naming a class.

    A class definition can include the following −

    • Fields − A field is any variable declared in a class. Fields represent data pertaining to objects
    • Constructors − Responsible for allocating memory for the objects of the class
    • Functions − Functions represent actions an object can take. They are also at times referred to as methods

    These components put together are termed as the data members of the class.

    Consider a class Person in typescript.

    classPerson{}

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var Person =(function(){functionPerson(){}return Person;}());

    Example: Declaring a class

    classCar{//field 
       engine:string;//constructor constructor(engine:string){this.engine = engine 
       }//function disp():void{console.log("Engine is  :   "+this.engine)}}

    The example declares a class Car. The class has a field named engine. The var keyword is not used while declaring a field. The example above declares a constructor for the class.

    A constructor is a special function of the class that is responsible for initializing the variables of the class. TypeScript defines a constructor using the constructor keyword. A constructor is a function and hence can be parameterized.

    The this keyword refers to the current instance of the class. Here, the parameter name and the name of the classs field are the same. Hence to avoid ambiguity, the classs field is prefixed with the this keyword.

    disp() is a simple function definition. Note that the function keyword is not used here.

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var Car =(function(){//constructorfunctionCar(engine){this.engine = engine;}//function
       Car.prototype.disp=function(){console.log("Engine is  :   "+this.engine);};return Car;}());

    Creating Instance objects

    To create an instance of the class, use the new keyword followed by the class name. The syntax for the same is given below −

    Syntax

    var object_name = new class_name([ arguments ])
    
    • The new keyword is responsible for instantiation.
    • The right-hand side of the expression invokes the constructor. The constructor should be passed values if it is parameterized.

    Example: Instantiating a class

    var obj =newCar("Engine 1")

    Accessing Attributes and Functions

    A classs attributes and functions can be accessed through the object. Use the . dot notation (called as the period) to access the data members of a class.

    //accessing an attribute 
    obj.field_name 
    
    //accessing a function 
    obj.function_name()
    

    Example: Putting them together

    classCar{//field 
       engine:string;//constructor constructor(engine:string){this.engine = engine 
       }//function disp():void{console.log("Function displays Engine is  :   "+this.engine)}}//create an object var obj =newCar("XXSY1")//access the field console.log("Reading attribute value Engine as :  "+obj.engine)//access the function
    obj.disp()

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var Car =(function(){//constructorfunctionCar(engine){this.engine = engine;}//function
       Car.prototype.disp=function(){console.log("Function displays Engine is  :   "+this.engine);};return Car;}());//create an objectvar obj =newCar("XXSY1");//access the fieldconsole.log("Reading attribute value Engine as :  "+ obj.engine);//access the function
    obj.disp();

    The output of the above code is as follows −

    Reading attribute value Engine as :  XXSY1 
    Function displays Engine is  :   XXSY1
    

    Class Inheritance

    TypeScript supports the concept of Inheritance. Inheritance is the ability of a program to create new classes from an existing class. The class that is extended to create newer classes is called the parent class/super class. The newly created classes are called the child/sub classes.

    A class inherits from another class using the extends keyword. Child classes inherit all properties and methods except private members and constructors from the parent class.

    Syntax

    class child_class_name extends parent_class_name
    

    However, TypeScript doesnt support multiple inheritance.

    Example: Class Inheritance

    classShape{ 
       Area:numberconstructor(a:number){this.Area = a 
       }}classCircleextendsShape{disp():void{console.log("Area of the circle:  "+this.Area)}}var obj =newCircle(223); 
    obj.disp()

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var __extends =(this&&this.__extends)||function(d, b){for(var p in b)if(b.hasOwnProperty(p)) d[p]= b[p];function__(){this.constructor = d;}
       d.prototype = b ===null? Object.create(b):(__.prototype = b.prototype,new__());};var Shape =(function(){functionShape(a){this.Area = a;}return Shape;}());var Circle =(function(_super){__extends(Circle, _super);functionCircle(){_super.apply(this, arguments);}
    	
       Circle.prototype.disp=function(){console.log("Area of the circle:  "+this.Area);};return Circle;}(Shape));var obj =newCircle(223);
    obj.disp();

    The output of the above code is as follows −

    Area of the Circle: 223
    

    The above example declares a class Shape. The class is extended by the Circle class. Since there is an inheritance relationship between the classes, the child class i.e. the class Car gets an implicit access to its parent class attribute i.e. area.

    Inheritance can be classified as −

    • Single − Every class can at the most extend from one parent class
    • Multiple − A class can inherit from multiple classes. TypeScript doesnt support multiple inheritance.
    • Multi-level − The following example shows how multi-level inheritance works.

    Example

    classRoot{ 
       str:string;}classChildextendsRoot{}classLeafextendsChild{}//indirectly inherits from Root by virtue of inheritance  var obj =newLeaf(); 
    obj.str ="hello"console.log(obj.str)

    The class Leaf derives the attributes from Root and Child classes by virtue of multi-level inheritance.

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var __extends =(this&&this.__extends)||function(d, b){for(var p in b)if(b.hasOwnProperty(p)) d[p]= b[p];function__(){this.constructor = d;}
       d.prototype = b ===null? Object.create(b):(__.prototype = b.prototype,new__());};var Root =(function(){functionRoot(){}return Root;}());var Child =(function(_super){__extends(Child, _super);functionChild(){_super.apply(this, arguments);}return Child;}(Root));var Leaf =(function(_super){__extends(Leaf, _super);functionLeaf(){_super.apply(this, arguments);}return Leaf;}(Child));var obj =newLeaf();
    obj.str ="hello";console.log(obj.str);

    Its output is as follows −

    Output

    hello
    

    TypeScript Class inheritance and Method Overriding

    Method Overriding is a mechanism by which the child class redefines the superclasss method. The following example illustrates the same −

    classPrinterClass{doPrint():void{console.log("doPrint() from Parent called")}}classStringPrinterextendsPrinterClass{doPrint():void{super.doPrint()console.log("doPrint() is printing a string")}}var obj =newStringPrinter() 
    obj.doPrint()

    The super keyword is used to refer to the immediate parent of a class. The keyword can be used to refer to the super class version of a variable, property or method. Line 13 invokes the super class version of the doWork() function.

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var __extends =(this&&this.__extends)||function(d, b){for(var p in b)if(b.hasOwnProperty(p)) d[p]= b[p];function__(){this.constructor = d;}
       d.prototype = b ===null? Object.create(b):(__.prototype = b.prototype,new__());};var PrinterClass =(function(){functionPrinterClass(){}
       PrinterClass.prototype.doPrint=function(){console.log("doPrint() from Parent called");};return PrinterClass;}());var StringPrinter =(function(_super){__extends(StringPrinter, _super);functionStringPrinter(){_super.apply(this, arguments);}
    	
       StringPrinter.prototype.doPrint=function(){
    
      _super.prototype.doPrint.call(this);console.log("doPrint() is printing a string");};return StringPrinter;}(PrinterClass));var obj =newStringPrinter();
    obj.doPrint();

    The output of the above code is as follows −

    doPrint() from Parent called 
    doPrint() is printing a string
    

    The static Keyword

    The static keyword can be applied to the data members of a class. A static variable retains its values till the program finishes execution. Static members are referenced by the class name.

    Example

    classStaticMem{static num:number;staticdisp():void{console.log("The value of num is"+ StaticMem.num)}} 
    
    StaticMem.num =12// initialize the static variable 
    StaticMem.disp()// invoke the static method

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var StaticMem =(function(){functionStaticMem(){}
    	
       StaticMem.disp=function(){console.log("The value of num is"+ StaticMem.num);};return StaticMem;}());
    
    StaticMem.num =12;// initialize the static variable
    StaticMem.disp();// invoke the static method

    The output of the above code is as follows −

    The value of num is 12
    

    The instanceof operator

    The instanceof operator returns true if the object belongs to the specified type.

    Example

    classPerson{}var obj =newPerson()var isPerson = obj instanceofPerson;console.log(" obj is an instance of Person "+ isPerson);

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var Person =(function(){functionPerson(){}return Person;}());var obj =newPerson();var isPerson = obj instanceofPerson;console.log(" obj is an instance of Person "+ isPerson);

    The output of the above code is as follows −

    obj is an instance of Person True 
    

    Data Hiding

    A class can control the visibility of its data members to members of other classes. This capability is termed as Data Hiding or Encapsulation.

    Object Orientation uses the concept of access modifiers or access specifiers to implement the concept of Encapsulation. The access specifiers/modifiers define the visibility of a classs data members outside its defining class.

    The access modifiers supported by TypeScript are −

    S.No.Access Specifier & Description
    1.publicA public data member has universal accessibility. Data members in a class are public by default.
    2.privatePrivate data members are accessible only within the class that defines these members. If an external class member tries to access a private member, the compiler throws an error.
    3.protectedA protected data member is accessible by the members within the same class as that of the former and also by the members of the child classes.

    Example

    Let us now take an example to see how data hiding works −

    classEncapsulate{ 
       str:string="hello"private str2:string="world"}var obj =newEncapsulate()console.log(obj.str)//accessible console.log(obj.str2)//compilation Error as str2 is private

    The class has two string attributes, str1 and str2, which are public and private members respectively. The class is instantiated. The example returns a compile time error, as the private attribute str2 is accessed outside the class that declares it.

    Classes and Interfaces

    Classes can also implement interfaces.

    interfaceILoan{ 
       interest:number}classAgriLoanimplementsILoan{ 
       interest:number 
       rebate:numberconstructor(interest:number,rebate:number){this.interest = interest 
    
      this.rebate = rebate 
    }}var obj =newAgriLoan(10,1)console.log("Interest is : "+obj.interest+" Rebate is : "+obj.rebate )

    The class AgriLoan implements the interface Loan. Hence, it is now binding on the class to include the property interest as its member.

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var AgriLoan =(function(){functionAgriLoan(interest, rebate){this.interest = interest;this.rebate = rebate;}return AgriLoan;}());var obj =newAgriLoan(10,1);console.log("Interest is : "+ obj.interest +" Rebate is : "+ obj.rebate);

    The output of the above code is as follows −

    Interest is : 10 Rebate is : 1