Typescript Method Overloading

Typescript Method Overloading

Interfaces, Method Overloading, and Implementing these Interfaces

The Setup

In a recent project, I was working on capturing points on a 2-D grid and calculating the distance between any two points. I created a Point type to capture the x and y coordinates and created a function to calculate the distance between two Point values.

typescript
1type Point = {
2    x: number;
3    y: number;
4}
5
6function distance(a: Point, b: Point): number {
7    return Math.sqrt(
8          Math.pow((b.x - a.x), 2)
9        + Math.pow((b.y - a.y), 2)
10    );
11}

As the project progressed, I realized there are situations when it would be easier if the distance() function would accept the coordinates as individual values (x1, y1,x2, y2,).

One option is to create two functions:

typescript
1function distanceBetweenPoints(a: Point, b: Point): number {
2    return distanceBetweenCoordinates(a.x, a.y, b.x, b.y);
3}
4
5function distanceBetweenCoordinates(x1: number, y1: number, x2: number, y2: number): number {
6    return Math.sqrt(
7          Math.pow((x2 - x1), 2)
8        + Math.pow((y2 - y1), 2)
9    );
10}

Creating different functions to calculate distance works but seems clumsy to me. Another approach is to update the original distance() function ...

typescript
1function distance(arg1: Point | number, arg2: Point | number, arg3?: number, arg4?: number): number {
2    //skipping the implementation...
3    return NaN; 
4}

Now, we have a single function distance() but I can hear you yelling ... "this a lame approach!" Correct. All of the following are valid calls to `distance()` but none makes sense...

typescript
1distance(1, 2);
2distance(1, 2, 3);
3distance({x:1,y:2}, 3);

The function distance() should accept two Point arguments, or four numeric arguments representing the two coordinates. To accomplish this, we use function overloading.

typescript
1function distance(a: Point, b: Point): number;
2function distance(x1: number, y1: number, x2: number, y2: number): number;
3function distance(arg1: Point | number, arg2: Point | number, arg3?: number, arg4?: number): number {
4    return 0;  // left for you to implement...
5}

Aside

I use function overloading often. It helps me express my logic - "this function will be used in the following ways..." But, I will admit that Typescript makes it a bit tricky to do function overloading - specifically in implementing the function using union type and optional parameters.

In C# the process is straight forward. We just implement a set of functions with the same name but different arguments.

csharp
1public double distance(Point a, Point b) {
2    return distance(a.x, a.y, b.x, b.y);
3}
4
5public double distance(double x1, double y1, double x2, double y2) {
6    return Math.Sqrt(
7          Math.Pow((x2 - x1), 2)
8        + Math.Pow((y2 - y1), 2)
9    );
10}

The Challenge

Write an interface that extends Point and includes a distanceTo() method that calculates the distance from the Point (expressed in the interface) to another coordinate. The methods should accept another Point argument or x and y arguments. Then implement the interface in a class.

Here is your outline ...

typescript
1interface IPointRef {
2    /* ... */
3}
4
5class PointRef implements IPointRef {
6    /* ... */
7
8	/* helper */
9    static toPoint(x: number, y: number): Point {
10        return { x, y };
11    }
12}

You can check your distance calculations using this online calculator

Bonus... Update PointRef to allow for three constructors:

  • Empty (initialize the coordinates to the origin)
  • Single Param - Point - (initializes the class to the argument's coordinates)
  • Two Params - x and y - (initializes the class to the coordinates represented by the coordinates)

popularity
On Fire
posted
Oct. 01, 2024