Search code examples
javascripttypescriptfunctionobjectoverloading

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);

Solution

  • 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