Skip to content

Suggestion: implicitly infer parameter types for the implementation signature of an overloaded method #7763

Description

@malibuzios

The current pattern for method overloading in a class is:

class Example {
    // Overload signatures:
    func(param1: number, param2: string): number;
    func(param1: number[], param2: boolean[]): number[];

    // Actual method implementation:
    func(param1: number | number[], param2: string |  boolean[]): number | number[] {
        ...
    }
}

However the implementation signature is only in practice beneficial for parameter references within the body of the function. E.g., even if the parameter types of the implementation signature were, say, all set to any:

func(param1: any, param2: any): any {
  ...
}

A caller is still bound by the overload signatures:

let example = new Example();
example.func("ABC", 123); // Error! no overload of 'func' matches the arguments

Suggestion:

The parameter and return type of the implementation signature could be implicitly inferred if they are not given an explicit type:

class Example {
    func(param1: number, param2: string): number;
    func(param1: number[], param2: boolean[]): number[];

    func(param1, param2) {
        let x = param1; // type of x is number | number[]
        let y = param2; // type of y is string | boolean[]

        return "ABC"; // Error: return type has been implicitly inferred to number | number[] 
    }
}

Having this would make it less cumbersome to define and maintain overloaded methods.

Has this ever been discussed before? and if so, what were the arguments against it?

Activity

  1. RyanCavanaugh commented on Apr 1, 2016

    @RyanCavanaugh
    Member

    Strangely I don't think anyone's ever proposed this. It makes a lot of sense.

    Just to write out the rules:

    • Each parameter has the type of the union formed by its corresponding parameters by position
    • If a signature is "too short", the parameter appears as optional (this matters for --strictNullChecks or whatever we call that flag)
    • A signature with a rest arg appears as having infinitely many optional parameters
    • Return type is inferred by the union of the return type signatures.
  2. DanielRosenwasser commented on Apr 3, 2016

    @DanielRosenwasser
    Member

    That's a good idea, given that it's what most people end up writing today.

    The downside of that is that you're still stuck with a union of every member, so you'd need to continue casting or doing type checks, whereas usually in JavaScript you discriminate your overloads based on some of the arguments you were given. Ideally, we'd be able to actually tie the uses of a variable to its potential overload as well.

    For instance, if I had

    function drawLine(startX: number, startY: number, endX: number, endY: number): void;
    function drawLine(start: { x: number; y: number }, end: { x: number; y: number }): void;
    function drawLine(a, b, c, d) {
        if (typeof a === "number") {
            // 'a', 'b', 'c', and 'd' have type 'number' here.
        }
        else {
            // 'a' and 'b' have type '{ x: number; y: number }.
            // 'c' and 'd have type 'undefined'.
        }
    }
  3. RyanCavanaugh commented on Apr 20, 2016

    @RyanCavanaugh
    Member

    Concern from the slog was that this could potentially introduce some very unwieldy types by default. Implementors may prefer any when their signatures are complex (though this is an easy type annotation to add)

  4. added
    Too ComplexAn issue which adding support for may be too complex for the value it adds
    and removed
    RevisitAn issue worth coming back to
    on Apr 3, 2017
  5. locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    SuggestionAn idea for TypeScriptToo ComplexAn issue which adding support for may be too complex for the value it adds

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions