Author: saqibkhan

  • 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
    
  • Extending Interfaces

    In TypeScript, interfaces are a powerful way to define the shape of objects and enforce type constraints. They allow us to specify the required properties and methods that an object must have. One interesting feature of interfaces is the ability to extend them, allowing us to create a combination of interfaces. Extending an interface is also known as interface inheritance.

    Interface inheritance allows you to create more specialized interfaces that inherit properties and methods from other interfaces.

    Syntax

    Use extends keyword to extend a single or multiple interfaces in TypeScript.

    interfaceNewInterfaceextendsExistingInterface{// Additional properties and methods}interfaceNewInterfaceextendsInterface1, Interface2,...{// Additional properties and methods}

    The syntax to create a new interface by extending an existing one is shown above. The syntax for extending multiple interfaces is also shown. The second syntax is to extend multiple interfaces.

    Extending a Single Interface

    We can achieve single interface inheritance by extending a single interface. Let’s start with a simple scenario where we have an interface called Shape that defines a common property color for various shapes. We want to create a new interface ColoredShape that extends Shape and adds an additional property name.

    Example

    Let’s see an example of extending the Shape interface to create the ColoredShape interface. In this example, we defined the Shape interface with a color property. Then, we created the ColoredShape interface by extending Shape and adding a name property. We instantiated an object square of type ColoredShape and assigned values to color and name properties. Finally, we accessed and printed the values of color and name using dot notation.

    interfaceShape{
       color:string;}interfaceColoredShapeextendsShape{
       name:string;}const square: ColoredShape ={
       color:"red",
       name:"Square",};console.log(square.color);console.log(square.name);

    On compiling, it will generate the following JavaScript code:

    var square ={
       color:"red",
       name:"Square"};console.log(square.color);console.log(square.name);

    Output

    red
    Square
    

    Extending Multiple Interfaces

    In TypeScript, we can also extend multiple interfaces to create a new interface that combines properties and methods from all the extended interfaces. This allows us to create more complex and specialized interfaces by reusing existing ones. This helps to achieve multiple interface inheritance in TypeScript.

    Example

    In the example below, we defined the Printable and Scanable interfaces, each with their respective methods. Then, we created the MultifunctionalDevice interface by extending both Printable and Scanable interfaces and adding a new method copy(). We implemented the MultifunctionalDevice interface in a class called Printer and provided the necessary implementations for all the methods. Finally, we instantiated an object of the Printer class and called the print(), scan(), and copy() methods.

    interfacePrintable{print():void;}interfaceScanable{scan():void;}interfaceMultifunctionalDeviceextendsPrintable, Scanable {copy():void;}classPrinterimplementsMultifunctionalDevice{print(){console.log("Printing...");}scan(){console.log("Scanning...");}copy(){console.log("Copying...");}}const printer =newPrinter();
    printer.print(); 
    printer.scan(); 
    printer.copy();

    On compiling, it will generate the following JavaScript code:

    var Printer =/** @class */(function(){functionPrinter(){}
       Printer.prototype.print=function(){console.log("Printing...");};
       Printer.prototype.scan=function(){console.log("Scanning...");};
       Printer.prototype.copy=function(){console.log("Copying...");};return Printer;}());var printer =newPrinter();
    printer.print();
    printer.scan();
    printer.copy();

    Output

    Printing...
    Scanning...
    Copying...
    

    Enhancing an Existing Interface

    We may often encounter situations where we want to enhance an existing interface by adding additional properties or methods. Extending the interface allows us to do so without modifying the original interface directly.

    Example

    In this example, we have an existing User interface with a name property. We extend the User interface to create an EnhancedUser interface, which adds an age property and a greet() method. By extending the interface, we can define an object user of type EnhancedUser that includes the properties and methods from both interfaces.

    interfaceUser{
       name:string;}interfaceEnhancedUserextendsUser{
       age:number;greet():void;}const user: EnhancedUser ={
       name:"John Wick",
       age:25,greet(){console.log(Hello, my name is ${this.name} and I'm ${this.age} years old.);}};
    
    user.greet();

    On compiling, it will generate the following JavaScript code:

    var user ={
       name:"John Wick",
       age:25,greet:function(){console.log("Hello, my name is ".concat(this.name," and I'm ").concat(this.age," years old."));}};
    user.greet();

    Output

    Hello, my name is John Wick and I'm 25 years old.
    

    Creating Composite Interfaces

    Extending interfaces can also be valuable when creating composite interfaces that combine properties and methods from multiple sources. This is particularly useful when working with external libraries or modules that provide their interfaces.

    Example

    In this example, we have four interfaces: Product, DiscountedProduct, ProductWithReviews, and FeaturedProduct. Each interface extends one or more existing interfaces, allowing us to create a composite interface with properties and methods from multiple sources. We then define an object product of the type FeaturedProduct, which incorporates all the properties defined in the extended interfaces.

    interfaceProduct{
       name:string;
       price:number;}interfaceDiscountedProductextendsProduct{
       discount:number;}interfaceProductWithReviewsextendsProduct{
       reviews:string[];}interfaceFeaturedProductextendsDiscountedProduct, ProductWithReviews {
       featured:boolean;}const product: FeaturedProduct ={
       name:"Smartphone",
       price:599,
       discount:50,
       reviews:["Great product!","Highly recommended."],
       featured:true};console.log(product.featured);console.log(product.reviews);

    On compiling, it will generate the following JavaScript code:

    var product ={
       name:"Smartphone",
       price:599,
       discount:50,
       reviews:["Great product!","Highly recommended."],
       featured:true};console.log(product.featured);console.log(product.reviews);

    Output

    true
    [ 'Great product!', 'Highly recommended.' ]
    

    Overriding Properties and Methods

    We can also override properties and methods inherited from the base interfaces when extending interfaces. This allows us to modify or provide different implementations for specific properties or methods in the extended interface.

    Example

    In the below example, we have an Animal interface with a name property and a makeSound() method. We extend the Animal interface to create a Dog interface. By overriding the makeSound() method in the Dog interface, we provide a different implementation specific to dogs. The object dog of type Dog can then be instantiated, and the overridden method will be invoked when called.

    interfaceAnimal{
       name:string;makeSound():void;}interfaceDogextendsAnimal{makeSound():void;}const dog: Dog ={
       name:"Buddy",makeSound(){console.log("Woof woof!");}};
    
    dog.makeSound();

    On compiling, it will generate the following JavaScript code:

    var dog ={
       name:"Buddy",makeSound:function(){console.log("Woof woof!");}};
    dog.makeSound();

    Output

    Woof woof!
    
  • Interfaces

    An interface is a syntactical contract that an entity should conform to. In other words, an interface defines the syntax that any entity must adhere to.

    Interfaces define properties, methods, and events, which are the members of the interface. Interfaces contain only the declaration of the members. It is the responsibility of the deriving class to define the members. It often helps in providing a standard structure that the deriving classes would follow.

    Lets consider an object −

    var person ={ 
       FirstName:"Tom", 
       LastName:"Hanks",sayHi:()=>{return"Hi"}};

    If we consider the signature of the object, it could be −

    { 
       FirstName:string, 
       LastName:string,sayHi()=>string}

    To reuse the signature across objects we can define it as an interface.

    Declaring Interfaces

    The interface keyword is used to declare an interface. Here is the syntax to declare an interface −

    Syntax

    interface interface_name { 
    }
    

    Example: Interface and Objects

    interfaceIPerson{ 
       firstName:string, 
       lastName:string,sayHi:()=>string}var customer:IPerson ={ 
       firstName:"Tom",
       lastName:"Hanks", 
       sayHi:():string=>{return"Hi there"}}console.log("Customer Object ")console.log(customer.firstName)console.log(customer.lastName)console.log(customer.sayHi())var employee:IPerson ={ 
       firstName:"Jim",
       lastName:"Blakes", 
       sayHi:():string=>{return"Hello!!!"}}console.log("Employee  Object ")console.log(employee.firstName);console.log(employee.lastName);

    The example defines an interface. The customer object is of the type IPerson. Hence, it will now be binding on the object to define all properties as specified by the interface.

    Another object with following signature, is still considered as IPerson because that object is treated by its size or signature.

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var customer ={ firstName:"Tom", lastName:"Hanks",sayHi:function(){return"Hi there";}};console.log("Customer Object ");console.log(customer.firstName);console.log(customer.lastName);console.log(customer.sayHi());var employee ={ firstName:"Jim", lastName:"Blakes",sayHi:function(){return"Hello!!!";}};console.log("Employee  Object ");console.log(employee.firstName);console.log(employee.lastName);

    The output of the above example code is as follows −

    Customer object 
    Tom 
    Hanks 
    Hi there 
    Employee  object 
    Jim  
    Blakes 
    Hello!!!
    

    Interfaces are not to be converted to JavaScript. Its just part of TypeScript. If you see the screen shot of TS Playground tool there is no java script emitted when you declare an interface unlike a class. So interfaces have zero runtime JavaScript impact.

    Interface and Objects

    Union Type and Interface

    The following example shows the use of Union Type and Interface −

    interfaceRunOptions{ 
       program:string; 
       commandline:string[]|string|(()=>string);}//commandline as string var options:RunOptions ={program:"test1",commandline:"Hello"};console.log(options.commandline)//commandline as a string array 
    options ={program:"test1",commandline:["Hello","World"]};console.log(options.commandline[0]);console.log(options.commandline[1]);//commandline as a function expression 
    options ={program:"test1",commandline:()=>{return"**Hello World**";}};var fn:any= options.commandline;console.log(fn());

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10//commandline as stringvar options ={ program:"test1", commandline:"Hello"};console.log(options.commandline);//commandline as a string array
    options ={ program:"test1", commandline:["Hello","World"]};console.log(options.commandline[0]);console.log(options.commandline[1]);//commandline as a function expression
    options ={ program:"test1",commandline:function(){return"**Hello World**";}};var fn = options.commandline;console.log(fn());

    Its output is as follows −

    Hello 
    Hello 
    World 
    **Hello World**
    

    Interfaces and Arrays

    Interface can define both the kind of key an array uses and the type of entry it contains. Index can be of type string or type number.

    Example

    interfacenamelist{[index:number]:string}var list2:namelist =["John",1,"Bran"]//Error. 1 is not type string  interfaceages{[index:string]:number}var agelist:ages; 
    agelist["John"]=15// Ok 
    agelist[2]="nine"// Error

    Interfaces and Inheritance

    An interface can be extended by other interfaces. In other words, an interface can inherit from other interface. Typescript allows an interface to inherit from multiple interfaces.

    Use the extends keyword to implement inheritance among interfaces.

    Syntax: Single Interface Inheritance

    Child_interface_name extends super_interface_name
    

    Syntax: Multiple Interface Inheritance

    Child_interface_name extends super_interface1_name, 
    super_interface2_name,,super_interfaceN_name
    

    Example: Simple Interface Inheritance

    interfacePerson{ 
       age:number}interfaceMusicianextendsPerson{ 
       instrument:string}var drummer =<Musician>{}; 
    drummer.age =27 
    drummer.instrument ="Drums"console.log("Age:  "+drummer.age)console.log("Instrument:  "+drummer.instrument)

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var drummer ={};
    drummer.age =27;
    drummer.instrument ="Drums";console.log("Age:  "+ drummer.age);console.log("Instrument:  "+ drummer.instrument);

    Its output is as follows −

    Age: 27 
    Instrument: Drums 
    

    Example: Multiple Interface Inheritance

    interfaceIParent1{ 
       v1:number}interfaceIParent2{ 
       v2:number}interfaceChildextendsIParent1, IParent2 {}var Iobj:Child ={ v1:12, v2:23}console.log("value 1: "+this.v1+" value 2: "+this.v2)

    The object Iobj is of the type interface leaf. The interface leaf by the virtue of inheritance now has two attributes- v1 and v2 respectively. Hence, the object Iobj must now contain these attributes.

    On compiling, it will generate following JavaScript code.

    //Generated by typescript 1.8.10var Iobj ={ v1:12, v2:23};console.log("value 1: "+this.v1 +" value 2: "+this.v2);

    The output of the above code is as follows −

    value 1: 12   value 2: 23
    
  • Arrow Functions

    Arrow functions are a concise way to write the anonymous functions in TypeScript. They are introduced in ES6 (ECMAScript 2015). They offer a shorter and more readable syntax compared to traditional function declarations. Arrow functions are also called lambda functions. Lambda refers to the anonymous functions in programming.

    Syntax

    You can define an arrow function using a fat arrow (=>). The fat arrow is used to separate function parameters from the function body (statements).

    (param1, param2,..., paramN)=> statement
    

    There are 3 parts to an arrow function −

    • Parameters − A function may optionally have parameters, param1, param2, …, paramN.
    • The fat arrow notation/lambda notation (=>) − It is also called as the goes to operator.
    • Statements − represent the functions instruction set

    Examples

    Let’s understand the arrow functions/ lambda function with the help of some examples in TypeScript −

    Example: Arrow function with single statement

    We can write an arrow function with single statement as follows −

    (x:number, y:number):number=> x +y;

    For a single statement, it’s optional to write the return keyword to return a value and braces (curly brackets. But if you are using braces, it is required to write the return keyword to return a value.

    (x:number, y:number):number=>{return x +y;}

    Let’s look at the following example −

    const add =(x:number, y:number):number=> x +y;console.log(add(20,30));

    On compiling, it will generate the following JavaScript code.

    constadd=(x, y)=> x + y;console.log(add(20,30));

    It will produce the following result −

    50
    

    Example: Arrow function with multiple statement

    You can write multiple statements using curly brackets. Also you need to write the return statement to return a value.

    In the example below, we defined an arrow function that accepts two parameters and returns their product.

    const multiply =(x:number, y:number):number=>{let res:number= x * y;return res;};console.log(multiply(5,6));

    On compiling, it will generate the following JavaScript code.

    constmultiply=(x, y)=>{let res = x * y;return res;};console.log(multiply(5,6));

    It will produce the following output −

    30
    

    Example: Arrow function with no parameter

    The parameters to the arrow functions are optional.

    In the example below, we have defined an arrow function that takes no parameter and return a string value.

    constgreet=()=>{return"Hello World!";}console.log(greet());

    On compiling, it will generate the same JavaScript code.

    The output of the above code example is as follows −

    Hello World!
    

    Example: Arrow function with a single parameter

    The following example show an arrow function that take a single parameter and returns the sum of the parameter and 10.

    const add =(x:number):number=>{return x +10;}console.log(add(5));

    On compiling, it will generate the following JavaScript code.

    constadd=(x)=>{return x +10;};console.log(add(5));

    The output of the above code example is as follows −

    15
    

    Example: Arrow function with multiple parameters

    In the below example, we defined an arrow function that accept three parameters and return their sum.

    let sum:number;constadd=(a:number, b:number, c:number)=>{
      sum = a + b + c;return sum;};let res =add(10,30,45);console.log("The result is: "+ res);

    On compiling, it will generate the following JavaScript code.

    let sum;constadd=(a, b, c)=>{
    
    sum = a + b + c;return sum;};let res =add(10,30,45);console.log("The result is: "+ res);</code></pre>

    The output of the above code example is as follows −

    The result is: 85
    

    Example: Arrow function with default parameters

    In the below example, we passed the default value of the parameters to the arrow function. When you will not pass the corresponding argument values, these default values will be used inside the function body.

    constmul=(a =10, b =15)=> a * b;console.log("mul(5, 8) = "+mul(5,8));console.log("mul(6) = "+mul(6));console.log("mul() = "+mul());

    On compiling, it will generate the same JavaScript code.

    The output of the above code example is as follows −

    mul(5, 8) = 40 
    mul(6) = 90 
    mul() = 150
    

    Applications of Arrow Functions

    Let's now discuss some application examples of the arrow function in TypeScript.

    Example: Arrow functions as callback function in other function

    Arrow functions (Lambda expressions) are also useful as callbacks in functions such as array methods (e.g., map, filter, reduce). Here's an example demonstrating their usage with the "map" method −

    const numbers =[1,2,3,4,5];const squaredNumbers = numbers.map(x => x * x);console.log(Original array: ${numbers});console.log(Squared array: ${squaredNumbers});

    On compiling, it will generate the same JavaScript code.

    The output of the above code example is as follows −

    Original array: 1,2,3,4,5
    Squared array: 1,4,9,16,25
    

    Example: Arrow functions in Class

    Arrow functions (lambda expressions) can be employed as class methods or object properties in TypeScript. Below is an example of a class that includes a method composed as a lambda expression −

    classCalculator{
       add =(x:number, y:number, z:number):number=> x + y + z;}const obj =newCalculator();console.log(The result is: ${obj.add(4, 3, 2)});

    On compiling, it will generate the following JavaScript code.

    classCalculator{constructor(){this.add=(x, y, z)=> x + y + z;}}const obj =newCalculator();console.log(The result is: ${obj.add(4, 3, 2)});

    It will produce the following output −

    The result is: 9
    

    Example: Implementing Higher Order Functions

    Higher-order functions which are functions that accept one or more functions as arguments and/or return a function as a result can be conveniently defined using lambda expressions in TypeScript.

    constapplyOp=(
      x:number, 
      y:number,operation:(a:number, b:number)=>number)=>{returnoperation(x, y);};const result1 =applyOp(10,20,(a, b)=> a + b);console.log(result1);const result2 =applyOp(10,20,(a, b)=> a * b);console.log(result2);

    On compiling it will generate the following JavaScript code.

    constapplyOp=(x, y, operation)=>{returnoperation(x, y);};const result1 =applyOp(10,20,(a, b)=> a + b);console.log(result1);const result2 =applyOp(10,20,(a, b)=> a * b);console.log(result2);

    The output of the above code example is as follows −

    30
    200
    

    Arrow functions are very useful in writing the anonymous functions.

  • Parameter Destructuring

    In TypeScript, parameter destructuring is unpacking the argument object into separate parameter variables. For example, suppose we have passed the object with multiple properties as an argument of any function. In that case, we can destructure the object in the parameter and access all required properties of the object in a separate variable.

    However, we can destructure the object properties or array passed as an argument of the function. Also, we have to define the type of every parameter using type annotation in TypeScript while destructuring the parameters. So it might not be very clear for beginners.

    Syntax

    You can follow the syntax below for parameter destructuring in TypeScript.

    functiongetObjValues({ key1, key2 }:{ key1:string; key2:number}){// use key1 and key2 as a variable}// calling the function with an objectgetObjValues({ key1:"Hello", key2:20});

    In the above syntax, we have passed the argument as a function. Users can see how we have destructured every object value in the parameter.

    Examples

    Now, we will look at the various examples of parameter destructuring and learn different uses of it.

    Example 1

    In the example below, we have created the printObjValues() function, which takes an object as a parameter. We are destructuring the object and storing the key values of the object in the parameter variables.

    Also, users can see how we have used the parameter values in the function.

    functionprintObjValues({ key1, key2 }:{ key1:string; key2:number}){console.log("The value of key1 is "+ key1);console.log("The value of key2 is "+ key2);}printObjValues({ key1:"Hello", key2:20});printObjValues({ key1:"TypeScript", key2:50});

    On compiling, it will generate the following JavaScript code

    functionprintObjValues(_a){var key1 = _a.key1, key2 = _a.key2;console.log("The value of key1 is "+ key1);console.log("The value of key2 is "+ key2);}printObjValues({ key1:"Hello", key2:20});printObjValues({ key1:"TypeScript", key2:50});

    The above code will produce the following output

    The value of key1 is Hello
    The value of key2 is 20
    The value of key1 is TypeScript
    The value of key2 is 50
    

    Example 2

    In the example below, we are destructuring the object values in the parameter variable, but we have also assigned the default values to the parameter variables. The default values of the param2 are default. So, if we dont pass the param2 key-values pair in the argument object, it will use the default value, and the code will execute without any error.

    Also, users can see that we have used the ? to make the param2 parameter optional.

    functiongetParams({
       param1,
       param2 ="default",}:{
       param1:boolean;
       param2?:string;}){console.log("The value of param1 is "+ param1);console.log("The value of param2 is "+ param2);}getParams({ param1:true, param2:"value"});getParams({ param1:false});

    On compiling, it will generate the following JavaScript code

    functiongetParams(_a){var param1 = _a.param1, _b = _a.param2, param2 = _b ===void0?"default": _b;console.log("The value of param1 is "+ param1);console.log("The value of param2 is "+ param2);}getParams({ param1:true, param2:"value"});getParams({ param1:false});

    The above code will produce the following output

    The value of param1 is true
    The value of param2 is value
    The value of param1 is false
    The value of param2 is default
    

    Example 3

    In this example, all parameters are optional. We have assigned the default object containing all keys and default values to the parameter variables. So, we can use the argument object with one, two, three, or no key-value pairs.

    Users can observe that we have invoked the function by passing the object containing various numbers of key-values pairs as an argument.

    // Creating the function whose all parameters are optional and initializing them with default values.functionsample_function({
    
      value1,
      value2,
      value3,}:{
      value1?:number;
      value2?:number;
      value3?:number;}={ value1:20, value2:30, value3:40}):number{let sum = value1 + value2 + value3;return sum;}console.log("The sum of default values is "+sample_function());console.log("The sum of 10000, 20302, and value3 is "+sample_function({ value1:10000, value2:20302}));console.log("The sum of 10, 20, and 25 is "+sample_function({ value1:10, value2:20, value3:25}));</code></pre>

    On compiling, it will generate the following JavaScript code

    // Creating the function whose all parameters are optional and initializing them with default values.functionsample_function(_a){var _b = _a ===void0?{ value1:20, value2:30, value3:40}: 
    
    _a, value1 = _b.value1, value2 = _b.value2, value3 = _b.value3;var sum = value1 + value2 + value3;return sum;}console.log("The sum of default values is "+sample_function());console.log("The sum of 10000, 20302, and value3 is "+sample_function({ value1:10000, value2:20302}));console.log("The sum of 10, 20, and 25 is "+sample_function({ value1:10, value2:20, value3:25}));</code></pre>

    The above code will produce the following output

    The sum of default values is 90
    The sum of 10000, 20302, and value3 is NaN
    The sum of 10, 20, and 25 is 55
    

    Example 4

    In this example, we are passing the object of lock type as a function parameter. The lock interface contains the lock_id and isDurable properties. We created the lockObj and passed it as an argument of the callLockFunc() function.

    In the callLockFunc() function, we have destructured the parameter object in the variables and print them to show its values.

    interfacelock{
       lock_id?:string;
       isDurable?:boolean;}let lockObj: lock ={
       lock_id:"4523fdr0",
       isDurable:true,};functioncallLockFunc(obj: lock){let{ lock_id, isDurable }= obj;console.log("The destructured lock_id value is "+ lock_id);console.log("The destructured isDurable value is "+ isDurable);}callLockFunc(lockObj);
    
    lockObj.isDurable =false;
    lockObj.lock_id ="eredf";callLockFunc(lockObj);

    On compiling, it will generate the following JavaScript code

    var lockObj ={
       lock_id:"4523fdr0",
       isDurable:true};functioncallLockFunc(obj){var lock_id = obj.lock_id, isDurable = obj.isDurable;console.log("The destructured lock_id value is "+ lock_id);console.log("The destructured isDurable value is "+ isDurable);}callLockFunc(lockObj);
    lockObj.isDurable =false;
    lockObj.lock_id ="eredf";callLockFunc(lockObj);

    The above code will produce the following output

    The destructured lock_id value is 4523fdr0
    The destructured isDurable value is true
    The destructured lock_id value is eredf
    The destructured isDurable value is false