How can I declare a class
type, so that I ensure the object is a constructor of a general class?
In the following example, I want to know which type should I give to AnimalClass
so that it could either be Penguin
or Lion
:
class Animal { constructor() { console.log("Animal"); } } class Penguin extends Animal { constructor() { super(); console.log("Penguin"); } } class Lion extends Animal { constructor() { super(); console.log("Lion"); } } class Zoo { AnimalClass: class // AnimalClass could be 'Lion' or 'Penguin' constructor(AnimalClass: class) { this.AnimalClass = AnimalClass let Hector = new AnimalClass(); } }
Of course, the class
type does not work, and it would be too general anyway.
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.
typeof Animal is a TypeScript type annotation which "returns" the type of the Animal constructor function.
Classes in TypeScript do not require you to explicitly write a constructor. However if you are extending a base class you will need to create a constructor to call super() at a minimum.
In TypeScript, the constructor method is always defined with the name "constructor". In the above example, the Employee class includes a constructor with the parameters empcode and name . In the constructor, members of the class can be accessed using this keyword e.g. this. empCode or this.name .
Edit: This question was answered in 2016 and is kind of outdated. Look at @Nenad up-to-date answer below.
Solution from typescript interfaces reference:
interface ClockConstructor { new (hour: number, minute: number): ClockInterface; } interface ClockInterface { tick(); } function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface { return new ctor(hour, minute); } class DigitalClock implements ClockInterface { constructor(h: number, m: number) { } tick() { console.log("beep beep"); } } class AnalogClock implements ClockInterface { constructor(h: number, m: number) { } tick() { console.log("tick tock"); } } let digital = createClock(DigitalClock, 12, 17); let analog = createClock(AnalogClock, 7, 32);
So the previous example becomes:
interface AnimalConstructor { new (): Animal; } class Animal { constructor() { console.log("Animal"); } } class Penguin extends Animal { constructor() { super(); console.log("Penguin"); } } class Lion extends Animal { constructor() { super(); console.log("Lion"); } } class Zoo { AnimalClass: AnimalConstructor // AnimalClass can be 'Lion' or 'Penguin' constructor(AnimalClass: AnimalConstructor) { this.AnimalClass = AnimalClass let Hector = new AnimalClass(); } }
I am not sure if this was possible in TypeScript when the question was originally asked, but my preferred solution is with generics:
class Zoo<T extends Animal> { constructor(public readonly AnimalClass: new () => T) { } }
This way variables penguin
and lion
infer concrete type Penguin
or Lion
even in the TypeScript intellisense.
const penguinZoo = new Zoo(Penguin); const penguin = new penguinZoo.AnimalClass(); // `penguin` is of `Penguin` type. const lionZoo = new Zoo(Lion); const lion = new lionZoo.AnimalClass(); // `lion` is `Lion` type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With