A constructor is a special function of the class that is automatically invoked when we create an instance of the class in Typescript. We use it to initialize the properties of the current instance of the class. Using the constructor parameter properties or Parameter shorthand syntax, we can add new properties to the class. We can also create multiple constructors using the technique of constructor method overload.
Table of Contents
Creating a Class Constructor
The constructor method in a class must have the name constructor. A class can have only one implementation of the constructor method. The constructor method is invoked every time we create an instance from the class using the new operator. It always returns the newly created object.
The following is an empty Person class with the method constructor. The constructor method prints Constructor is called
. As you can see every time we execute the statement new Person()
the message is printed on the console.
1 2 3 4 5 6 7 8 9 10 11 12 | class Person { constructor() { console.log("Constructor is called") } } let p1= new Person() //contructor is called let p2= new Person() //contructor is called |
The constructor method creates the instance of the object with the property defined in the class. We can access the current instance using the ‘this
‘ inside the constructor. Once finished constructor function returns the new object.
Parameters to the Constructor method
Constructors are just like normal functions in the way that they also accept parameters. We need to pass parameter values when we create a new class instance.
The constructor function in the following example accepts two arguments. We use the ‘this
‘ keyword to get the current instance of the class and initialize its properties using those parameters.
1 2 3 4 5 6 7 8 9 10 11 | class Person { firstName:string; lastName:string; constructor(fName:string, lName:string) { this.firstName=fName; this.lastName=lName; } } |
We create an instance from the class by invoking the new
operator on the Person
class. In the argument, we will pass values for fName
& lName
arguments. The new Person
will invoke the constructor function associated with the class Person
along with the arguments.
1 2 3 4 | let p= new Person("Jon","Snow") console.log(p) //Person: { "firstName": "Jon", "lastName": "Snow" } |
The parameter in the constructor is not optional here. This means that when you instantiate the class, you must pass the values of all arguments to the constructor. If you do not pass all parameters, then it will result in a compiler error.
1 2 3 | let p= new Person("Jon") //Expected 2 arguments, but got 1. |
In the following example, we have added a few console.log statements in the constructor method to display the value of ‘this
‘ property after each statement.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class Person { firstName:string; lastName:string; constructor(fName:string, lName:string) { console.log("contructor is called") console.log(this) this.firstName=fName; console.log(this) this.lastName=lName; console.log(this) } } let p= new Person("Jon","Snow") //"contructor is called" //Person: {} //Person: { "firstName": "Jon"} //Person: { "firstName": "Jon", "lastName": "Snow"} |
Constructor Parameter Properties
Constructor Parameter Properties (or Property Shorthand syntax) offers a special shorthand syntax to convert parameters of constructor function into properties. We can do this by prefixing a constructor parameter with one of the visibility modifiers ( i.e. public
, private
, protected
, or readonly
). The resulting field gets those modifier(s)
In this example, we have created the firstName
& lastName
fields manually
1 2 3 4 5 6 7 8 9 10 11 | class Person { firstName:string; lastName:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } } |
Instead, we can prefix the constructor parameters with the public modifier. Typescript automatically creates the properties for us
1 2 3 4 5 6 7 8 9 10 | class Person { constructor(public firstName:string, public lastName:string) { } } let p = new Person("Jon", "Snow"); console.log(p) //Person: { "firstName": "Jon", "lastName": "Snow" } |
Passing Default Values in the Constructor method
We can also pass the default value to the constructor method. In this example x
& y
properties are initialized with the 10 & 20 if we do not pass any values while creating the new instance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Point { x: number; y: number; constructor(x = 10, y = 20) { this.x = x; this.y = y; } } //Using default Values let p1 = new Point(); console.log(p1) //Point: { "x": 10, "y": 20 } let p2 = new Point(100,200); console.log(p2) //Point: { "x": 100, "y": 200 } |
Constructor functions in the derived class
The derived class must call the constructor of the parent class (base class). We do this by invoking the super
method. We must call the super method before we use ‘this
‘ variable.
In this example, the Employee
class extends the Person
class and adds its own property designation
. Here Employee
class must invoke the constructor of the Person class. To do that we use the super
function. The super function needs to be invoked with the parameters of the Person
constructor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class Person { firstName:string; lastName:string; constructor(firstName:string, lastName:string) { this.firstName=firstName; this.lastName=lastName; } } class Employee extends Person { designation:string; constructor(firstName:string, lastName:string, designation:string) { super(firstName,lastName) // call parent class constructor this.designation=designation; } } let e = new Employee("Jon","Snow","Manager") console.log(e) //Employee: { "firstName": "Jon", "lastName": "Snow", "designation": "Manager" } |
Call the super method before accessing ‘this’ or before we return from the derived constructor. Trying to access the variable ‘this’ will result in both compile-time and run-time errors ( “‘super’ must be called before accessing ‘this’ in the constructor of a derived class“).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Employee extends Person { designation:string; constructor(firstName:string, lastName:string, designation:string) { //Both compiler and run time error console.log(this) //'super' must be called before accessing 'this' in the constructor of a derived class. super(firstName,lastName) // call parent class constructor this.designation=designation; } } |
Not invoking the super
call in the derived class will also result in a compiler error “Constructors for derived classes must contain a ‘super’ call“
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Employee extends Person { designation:string; constructor(firstName:string, lastName:string, designation:string) { this.designation=designation; } } //Constructors for derived classes must contain a 'super' call. |
Class without constructor
You can create a class without a constructor method. In such cases, JavaScript (not TypeScript) automatically uses a default constructor.
The default constructor is an empty constructor.
1 2 3 4 | constructor() { } |
But if the class is a derived class then the default constructor is as shown below
1 2 3 4 5 | constructor(...args) { super(...args); } |
Multiple Constructor methods
A class can have only one implementation of the constructor method. Having more than one constructor function will result in an error. You cannot use the name constructor in a getter or setter method.
But we can take advantage of function overload to create multiple overload signatures of the constructor function.
In this example, the person class has only one property i.e. name
. We would like to create the instance of the class either with a name
or with a firstName
& lastName
.
To do that, first, we need to create two constructor function signatures (overload signatures) one for each use case. Then an actual constructor function (implementation function) where you write the implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class Person { name:string; constructor(name:string); //constructor function signature 1 constructor(firstName:string,lastName:string); //constructor function signature 2 constructor(name:string, lastName?:string) { //actual constructor function if (lastName) { this.name=name+" "+lastName } else { this.name=name; } } } let p = new Person("Jon", "Snow"); console.log(p) //Person: { "name": "Jon Snow" } p = new Person("Samwell Tarly"); console.log(p) //Person: { "name": "Samwell Tarly" } |
Note that a parameter property is only allowed in a constructor implementation. For example, prefixing the public modifier to the name property in the constructor function signature results in a compiler error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Person { constructor(public name:string); //Error constructor(firstName:string,lastName:string); constructor(name:string, lastName?:string) { if (lastName) { this.name=name+" "+lastName } else { this.name=name; } } } //<strong>parameter property</strong> is only allowed in a constructor implementation |
You can prefix the public modifier to the name property only in the constructor implementation function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Person { constructor(name:string); constructor(firstName:string,lastName:string); constructor(public name:string, lastName?:string) { //ok if (lastName) { this.name=name+" "+lastName } else { this.name=name; } } } |
You can refer to function or method overloading in TypeScript for more
Perfect guide