How to Have Type for Class Constructor in TypeScript
TypeScript has a strongly typed language, and thus every variable and object used in TypeScript has a type, which helps in further debugging and avoiding runtime errors in the application. This tutorial will focus on how to have types for constructors in TypeScript.
Typed Constructor in TypeScript
Normally when we pass objects to a constructor of a class with types. We can have multiple types, even using the union operator.
Code:
interface AcademyInfo {
name : string;
country: string;
}
class Academy {
private id;
private info;
private numStudents;
constructor( info : AcademyInfo, id : string | number, numStudents? : number){
this.id = id;
this.info = info;
this.numStudents = numStudents ?? 0;
}
public getAcademyName(){
return this.info.name;
}
}
var academy = new Academy( {name : "Augustine Academy", country: "India"}, "3232dqsx23e", 1000 );
There’s a constructor which supports parameters of varying types such as AcademyInfo
, string | number
, and number
. All these variables can be passed to the constructor of the class when creating instances of the class.
Type for Constructor of a Class in TypeScript
The constructors of class can have types of their own.
Syntax:
type ConstructorType<T> = new (...args : any[]) => T;
Above syntax, generic types are used, indicating that the constructor will return an object that can be a class instance of type T
. Using the typed constructor, one can implement the factory design pattern in TypeScript.
Code:
interface Animal {
speak() : void;
}
interface AnimalConstructor {
new ( speakTerm : string, name : string, legs: number ) : Animal;
}
const createAnimalFactory = (
ctor : AnimalConstructor,
name : string,
legs : number,
speakTerm : string
) => {
return new ctor(speakTerm, name, legs);
};
class Dog implements Animal{
private name;
private legs;
private speakTerm;
constructor(speakTerm : string, name : string, legs : number){
this.speakTerm = speakTerm;
this.legs = legs;
this.name = name;
}
speak(){
console.log( "Dog " + this.speakTerm + " I have " + this.legs + " legs");
}
}
class Cat implements Animal{
private name;
private legs;
private speakTerm;
constructor(speakTerm : string, name : string, legs : number){
this.speakTerm = speakTerm;
this.legs = legs;
this.name = name;
}
speak(){
console.log( "Cat " + this.speakTerm + " I have " + this.legs + " legs");
}
}
const dog = createAnimalFactory(Dog, "dog", 2, "woof");
const cat = createAnimalFactory(Cat, "cat", 2, "meow");
dog.speak();
cat.speak();
Output:
"Dog woof I have 2 legs"
"Cat meow I have 2 legs"
We have two classes in the above example named Dog
and Cat
, both implementing the same interface Animal
and having different implementations of the speak
method.
In the createAnimalFactory
method, one can just pass the Dog
or the Cat
class along with its parameters to create an instance of that particular class.
This design pattern is very useful for making different instances of classes depending on some use case.