ProgrammingBackend Developer

How to implement method overloading in TypeScript classes, what mistakes should be avoided when writing overloaded methods, and what nuances of type consideration may occur?

Pass interviews with Hintsage AI assistant

Answer.

Background:

TypeScript supports method overloading, similar to other strictly typed languages (like Java or C#), but the syntax for overloading in TypeScript is conceptually different. It allows multiple signatures, but only one implementation. This can confuse developers familiar with classical overloading.

Issue:

A common mistake is attempting to define multiple methods with different sets of parameters. This results in a compilation error, as TypeScript requires one implementation that fulfills all signature variations.

Solution:

Overloading is achieved by declaring multiple method signatures followed by an implementation that fulfills all variations. To correctly differentiate parameters, type guards or instanceof are usually applied.

Example code:

class MyLogger { log(message: string): void; log(message: string, level: 'info' | 'error'): void; log(message: string, level?: 'info' | 'error'): void { const lvl = level ?? 'info'; console.log(`[${lvl}] ${message}`); } }

Key features:

  • Only one implementation of the method, but multiple declaration signatures.
  • Need to handle all variations of input parameters within the implementation.
  • Types in the implementation should be as broad as possible.

Trick Questions.

Is it possible to implement two implementations of the same method with different sets of parameters?

No. In TypeScript, only one implementation is allowed. Multiple methods with the same name are a syntax error.

How to type rest parameters when overloading methods to avoid losing strict typing?

It is recommended to describe exact parameters in signatures, and in the implementation — the most generalized:

class Test { doWork(a: number): void; doWork(a: string): void; doWork(a: number | string): void { //... } }

What will happen if the return type of overloaded signatures is different?

TypeScript will require that the implementation returns a union type. Otherwise, a compilation error occurs.

class X { get(value: number): string; get(value: string): number; get(value: number | string): string | number { return typeof value === 'number' ? 'number' : 42; } }

Common mistakes and anti-patterns

  • Mismatch of implementation with overload signatures.
  • Multiple separate implementations of one method.
  • Ignoring type checks of input parameters within the method body.

Real-life Example

Negative case

In the product, there was an attempt to implement two methods with the same name for different parameter types in a class. After compilation, the method "replaced" the last declaration, all other versions were ignored, leading to bugs.

Advantages:

  • Familiar style for some languages.

Disadvantages:

  • Does not work completely in TypeScript, compiles with errors.
  • Increased risk of missed cases.

Positive case

Multiple signatures with union-type parameters were made, and all variations were handled in the method through type guards. The compiler immediately warned about type issues.

Advantages:

  • Strict type control.
  • Safety.
  • Ease of testing.

Disadvantages:

  • Requires more code to check variations.