Please allow more permissive function overloading

Topics: Language Specification
Mar 11, 2014 at 11:17 PM
Dear TypeScript Team,

I love TypeScript, and I've been using it daily since the 0.8 release. It has given my client-side programming experience a total makeover. Thank you for that.

The issue that I am bringing up today concerns function overloading, and I imagine you've heard this complaint before.

Please please please allow more permissive function and method overloading. There are times when designing an api where you need to have one method do multiple things. And these different uses do not use argment and return types that are assignable to each other.

This is a problem I run into all the time. Perhaps the simplest case I can think of is a function that could take a string or an int as a parameter:

Right now, I would write this function like this:
module Module {
    export function overloadedFunction(value: number);
    export function overloadedFunction(value: string);

    //For overload resolution only
    export function overloadedFunction(value: any) {
            //Do something with a string or a number
    }
}
The problem with this code is that no compiler error is issued if the caller changes the argument to a type other than a string or a number, which is clearly the behavior that the author intended.

Please allow one of these two solutions to be valid. I am truly begging you.
//Any set of method signatures are valid overloads
module Module {
    export function overloadedFunction(value: number);
    export function overloadedFunction(value: string) {
            //Do something with a string or a number
    }
}
Or
//Functions and methods can have private overloads
module Module {
    export function overloadedFunction(value: number);
    export function overloadedFunction(value: string);

    //The overly permissive overload is declared as private
    function overloadedFunction(value: any) {
            //Do something with a string or a number
    }
}
In the first case, it is the callers responsibility to enforce the function/method signatures they have specified. I think this is perfectly reasonable.

In the second case, the overly permissive overload is declared either to not be exported, or to be private in the case of a method. Therefore the caller is exposed to it, and the compiler will enforce only the public overloads.

While I would prefer the first case, the second seems like a much easier change for the existing compiler.

One argment that could be made against the second case is that the caller still has access to the method overload, whether they can see it or not. This is true. But users have access to private member variables, despite the fact that the TypeScript compiler won't allow it. This fact did not prevent the private member feature from being implemented.

Please consider these two alternatives. Overloading is a such an important feature, and the way it is currently implemented in TypeScript is far too restrictive to allow us developers to utilize it to its full potential.

Thank you for your consideration.

Sincerely,
Doug Rubino
Coordinator
Mar 12, 2014 at 6:13 PM
Edited Mar 12, 2014 at 6:13 PM
There is generally some confusion around overload lists and what they mean. We actually already handle this as you suggest. The overload list and the function declaration are distinct. In this example, the function only has two overloads, not three:
module Module {
    export function overloadedFunction(value: number);
    export function overloadedFunction(value: string);

    //For overload resolution only
    export function overloadedFunction(value: any) {
            //Do something with a string or a number
    }
}
You can see this in the intellisense. The 'value: any' is actually part of the function declaration and does not change the overload set. Instead, it only affects how we treat the parameter inside the function. This is a way of letting the user describe the declaration that is, if you will, a union of all the overloads.

You can also see this by trying to call the function with the wrong type:
module Module {
    export function overloadedFunction(value: number);
    export function overloadedFunction(value: string);

    //For overload resolution only
    export function overloadedFunction(value: any) {
            //Do something with a string or a number
    }
}

Module.overloadedFunction({x: 4});  //<-- error, supplied parameter does not match
In the above, I'm passing an object. While this matches 'any', the 'any' isn't actually one of the overloads. Instead, the object has to match one of either number or string, which it doesn't, and we throw an error.
Mar 13, 2014 at 1:55 AM
Thank you for the clarification!