ProgrammingFrontend/Fullstack Developer

How does constructor typing work in TypeScript and what difficulties can arise during inheritance?

Pass interviews with Hintsage AI assistant

Answer.

Background

Initially, JavaScript did not have strict typing for classes and their constructors, which led to runtime errors. TypeScript introduced a type system for safer programming and supported constructor typing with inheritance, which is important for large application development.

The Problem

Constructor typing in TypeScript requires simultaneous consideration of the constructor signature, the type of the created instance, and inheritance specifics. Problems arise when the constructor signatures in the base and derived classes diverge, or when only the return type is typed and not the constructor's input parameters.

Solution

In TypeScript, constructors can be explicitly typed through special signatures using the expression new (...args: any[]) => T. When inheriting, it's important to maintain consistency in signatures and correctly extend base classes.

Example code:

class Animal { constructor(public name: string) {} } class Dog extends Animal { constructor(name: string, public breed: string) { super(name); } } // Constructor type function createInstance<T>(C: new (...args: any[]) => T, ...args: any[]): T { return new C(...args); } const dog = createInstance(Dog, 'Rex', 'Labrador');

Key features:

  • Constructor signature is a separate entity declared through new
  • Compliance of parameters between base and derived constructors
  • Ability to generically create instances via typed constructors

Tricky Questions.

Can you declare multiple constructors in a class, like in Java or C#?

No, TypeScript does not support multiple constructors. To simulate overloading, overload signatures are used with a single implementation. The correct approach:

class Example { constructor(x: string); constructor(x: number); constructor(x: number | string) { // One implementation } }

Can you type only the return type of the constructor, ignoring the parameters?

No, the constructor signature must include parameters. Example of correct typing:

interface Constructable<T> { new (...args: any[]): T; }

If you declare a constructor in a child class without calling super, what will happen?

There will be a compilation error: the subclass constructor must call super before accessing this.

Common Errors and Anti-Patterns

  • Inconsistent constructor parameters between base and derived classes
  • Missing call to super in the child constructor
  • Incorrect constructor typing when abstracting through factories

Real-life Example

Negative Case

In the project, a base class Animal with a constructor (name) was used, but in the derived class Dog (name, breed) was added without properly extending the signature.

Pros:

  • Documents new parameters

Cons:

  • Breaks compatibility when creating instances through generic factories, errors at compile time.

Positive Case

The constructor type was separated out, the factory createInstance was parameterized through CorrectConstructable<T>, and the signatures were adhered to.

Pros:

  • Type safety, predictable behavior
  • Easy to write generic functions

Cons:

  • Requires more thorough type consideration