How to overload methods in Typescript?

Asked

Viewed 1,353 times

9

I’m having trouble overloading methods in Typescript.

The method to be overloaded is a Object Factory rect() one signature has four numerical parameters and the other signature has only one parameter of the defined structure object type.

/**
 * Esse é um dos métodos que quero sobrecarregar,
 * com quatro parametros na assinatura.
 *
 * @param left 
 * @param top 
 * @param width 
 * @param height 
 */
static rect(left: number, top: number, width: number, height: number): Rect2D {
    return new Rect2D(left, top, width, height);
}

/**
 * Esse é segundo método para sobrecarga,
 * conta com apenas um parâmetro estruturado na assinatura.
 *
 * @param param0 
 */
static rect({ left, top, width, height }: { left: number; top: number; width: number; height: number; }): Rect2D {
    return new Rect2D(left, top, width, height);
}

How to do this overhead since the way I am doing results in the following error message:

Duplicate Function implementation.ts(2393)

I believe it is not relevant to the answer but if anyone asks here is the context fragment containing the methods to be overloaded:

 class Point2D{
    
    private _x : number;
    public get x() : number {
        return this._x;
    }
    public set x(v : number) {
        this._x = v;
    }

    
    private _y : number;
    public get y() : number {
        return this._y;
    }
    public set y(v : number) {
        this._y = v;
    }
    
    
    constructor(x: number, y: number){
        this._x = x;
        this._y = y;
    }
}

class Rect2D implements IRect2D{
    private _position: Point2D;
    public get position(): Point2D {
        return this._position;
    }
    public set position(value: Point2D) {
        this._position = value;
    }

    private _size: Size;
    public get size(): Size {
        return this._size;
    }
    public set size(value: Size) {
        this._size = value;
    }
    
    /**
     * Esse é um dos métodos que quero sobrecarregar,
     * com quatro parametros na assinatura.
     *
     * @param left 
     * @param top 
     * @param width 
     * @param height 
     */
    static rect(left: number, top: number, width: number, height: number): Rect2D {
        return new Rect2D(left, top, width, height);
    }

   /**
    * Esse é segundo método para sobrecarga,
    * conta com apenas um parâmetro estruturado na assinatura.
    *
    * @param param0 
    */
    static rect({ left, top, width, height }: { left: number; top: number; width: number; height: number; }): Rect2D {
        return new Rect2D(left, top, width, height);
    }

    private constructor(left: number, top: number, width: number, height: number ){
        this._position.x = left;
        this._position.y = top;
        this._size.width = width;
        this._size.height = height;
    }
}
  • 1

    Does this help or duplicate? https://answall.com/q/365879/101 and https://answall.com/q/158075/101

1 answer

5


Collection of information

In the repository of project of Microsoft Typescript the language is defined as a superset of Javascript, adding optional types to Javascript and its code is compiled for readable Javascript, based on standards.

In the documentation Mozilla on inheritance in the Javascript It is written that in Javascript there are no "methods" like the ones we know in class-based languages. In Javascript, any function can be added to an object in the form of property. An inheritance of functions acts as the inheritance of any properties other than functions, and we can even perform over-writing function. But the documentation doesn’t mention the overhead.

Searching the internet about overloading methods in Javascript I found these phrase on Stackoverflow in English:

You cannot overload the method in the strict sense. It is not the way it is supported in Java or C#.

The problem is that Javascript NAY natively supports overload of methods. Therefore, if you view / analyze two or more functions with the same name, only consider the last function defined and replace the previous ones.

As Typescript is a superset of Javascript and existing Javascript programs are also valid, so the same rule that rules away method overload for the benefit of Javascript method overwriting is valid in Typescript.

All that is written above is true, but then I got in the comments the link to the following question How to use constructor overload in Typescript? and there are defined two fundamental concepts to understand what was my error of conception for the overload problem in Typescript.

In that reply came to me:

You need to keep in mind that Typescript code will compile for Javascript. The only way that Javascript has to differentiate overload is by the amount of parameters.

And extending that one reply for methods in general I definitely came out of the well where I was:

Typescript did not solve this problem that already existed in JS. Normal Typescript Overload is just making it easy to call a constructor with slightly different constructions, why only the latter can have an implementation. All others need to call the single builder.

Problem solving

Other than C# or Java the Typescript does not allow there to be a differentiated implementation for superscript methods, this information can be checked and found scattered in the section Advanced Types in Typescript documentation.

Then I won’t be able to do it here...

static rect(left: number, top: number, width: number, height: number): Rect2D {
    return new Rect2D(left, top, width, height);
}

static rect({ left, top, width, height }: { left: number; top: number; width: number; height: number; }): Rect2D {
    return new Rect2D(left, top, width, height);
}

Typescript does not allow a differentiated implementation for each method, because even if it were allowed to transpose the code to Javascript the last implementation of the sebrescreveria method would be the first implementation.

So it’s like in Javascript I must create a single method as comprehensive as possible in relation to the parameters, method that will be responsible for implementing all the overheads deciding what to do and when to do based on the type of parameters passed taking into account the rigid typification of parameters offered by the language.

The solution is this:

/**
 * São declaradas apenas as assinatura das sobrecargas para o método rect.
 * Essas são as assinaturas que vão estar disponíveis para o Intellisense.
 */
static rect({ left, top, width, height }: { left: number; top: number; width: number; height: number; }): Rect2D;
static rect(left: number, top: number, width: number, height: number):Rect2D;    
static rect(point: Point2D, size: Size):Rect2D;

/**
 *  Essa é implementação comum a toda as sobrecargas
 *  Essa assinatura NÃO será disponibilizada pelo Intellisense, 
 *sendo assim o apresentará apenas três sobrecargas para o ambiente de desenvolvimento 
 *  A quantidade de parâmetro deve ser igual a quantidade de parâmetros da 
 *sobrecarga cujo a assinatura contenha mais parâmetros.
 *  O parâmetro arg1 é obrigatório enquanto os parâmetros arg2, arg3 e arg4 são 
 *marcados como opcionais pois a sobrecarga que exige a menor quantidade de parâmetros
 *exige ao menos um parâmetro. Caso houvesse uma sobrecarga de assinatura rect()
 *arg1 também deveria ser opcional.
 */
static rect(arg1: any, arg2?: any, arg3?: any, arg4?: any):Rect2D{
    //verifica o tipo do primeiro para determinar qual a sobrecarga utilizada
    switch(typeof arg1){
        case "number": 
            // Se o primeiro parâmetro for numérico a sobrecarga será rect(left: number, top: number, width: number, height: number)
            return new Rect2D(arg1, arg2, arg3, arg4);
        case "object": 
            // Se o primeiro parâmetro for objeto tenho duas possiveis implemetações
            if (arg1 instanceof Point2D){
                // Caso o objeto seja do tipo Point2D
                return new Rect2D(arg1.x, arg1.y, arg2.width, arg2.height);
            } else {
                      // Baseado na forte tipagem da linguagem presumisse que o argumento é o destructuring object 
                      //{ left, top, width, height }: { left: number; top: number; width: number; height: number; }
                      return new Rect2D(arg1.left, arg1.top, arg1.width, arg1.height);
                   }

    }
    //Código de guarda, caso o usuário da lib entre com uma composição 
    //parâmetros absurda retorna um objeto default.
    return new Rect2D(0,0,0,0); 
} 

Test code for fragment no Repl.it

Browser other questions tagged

You are not signed in. Login or sign up in order to post.