labmember000
labmember000

Reputation: 35

How to overload a JavaScript function that is defined in an object

I've defined some functions in this object inside a function calculator because I want to chain them. My goal is to to overload the addNumber function but I can't seem to get the syntax right.

Below is an example of what I want to achieve (won't work because syntax is wrong)

const calculator = () => {
    return {
        result: 0,
        addNumber(a: number) : number;
        addNumber(a: number | b: number): number;
        addNumber(a: number | b: string): number {
            // Implementation to add numbers depending on function overload
            return this;
        },

        multiplyNumber(a) {
            this.result = this.result * a;
            return this;
        },

        log() {
             console.log(this.result);
        }
    };
}

// logs 10
calculator().addNumber(10).log();

// logs 25
calculator().addNumber(10,15).log();

// logs 25
calculator().addNumber(10,'15').log();

This is was the example that gave me the idea however, the function is defined normally. What are some ways I can overload a function that is defined in object?

function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d);
  } else {
    return new Date(mOrTimestamp);
  }
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3);

Upvotes: 2

Views: 510

Answers (2)

Cem Frt
Cem Frt

Reputation: 31

(() => {
  //array that store functions
    var Funcs = []
     /**
     * @param {function} f overload function
     * @param {string} fname overload function name
   * @param {parameters} vtypes function parameters type descriptor (number,string,object....etc
     */
    overloadFunction = function(f, fname, ...vtypes) {
        var k,l, n = false;
        if (!Funcs.hasOwnProperty(fname)) Funcs[fname] = [];
        Funcs[fname].push([f, vtypes?vtypes: 0 ]);
        window[fname] = function() {
            for (k = 0; k < Funcs[fname].length; k++)
                if (arguments.length == Funcs[fname][k][0].length) {
                    n=true;
                    if (Funcs[fname][k][1]!=0)
                    for(i=0;i<arguments.length;i++)
                    {
                        if(typeof arguments[i]!=Funcs[fname][k][1][i])
                        {
                            n=false;
                        }
                    }
                    if(n) return Funcs[fname][k][0].apply(this, arguments);
                }
        }
    }
})();

//First sum function definition with parameter type descriptors
overloadFunction(function(a,b){return a+b},"sum","number","number")
//Second sum function definition with parameter with parameter type descriptors
overloadFunction(function(a,b){return a+" "+b},"sum","string","string")
//Third sum function definition (not need parameter type descriptors,because no other functions with the same number of parameters
overloadFunction(function(a,b,c){return a+b+c},"sum")

//call first function
console.log(sum(4,2));//return 6
//call second function
console.log(sum("4","2"));//return "4 2"
//call third function
console.log(sum(3,2,5));//return 10
//ETC...

Upvotes: 0

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249656

If you are willing to switch to an anonymous class, then it's pretty simple to get overloading:

const calculator = () => {
    return new class {
        result = 0;

        addNumber(a: number) : this
        addNumber(a: number, b: number): this
        addNumber(a: number, b: string): this
        addNumber(a: number, b?: number | string): this {
            // Implementation to add numbers depending on function overload
            return this;
        }

        multiplyNumber(a: number) {
            this.result = this.result * a;
            return this;
        }

        log() {
             console.log(this.result);
        }
    };
}

Playground Link

Object literal methods and function expressions don't support overloading. The only other option is to use a function expression with a type assertion:

const calculator = () => {
    return {
        result: 0,

        addNumber : function (a: number, b?: number | string) {
            return this;
        } as {
            <T>(this: T, a: number) : T
            <T>(this: T, a: number, b: number): T
            <T>(this: T, a: number, b: string): T
        }
    };
}

Playground Link

Upvotes: 2

Related Questions