Skip to content

Extended type parameters don't work as constraints with overloads #7378

Closed

Description

@falsandtru

TypeScript Version:

master

Code

interface I {
  toString(): number;
}
function f<T extends number>(p: void) // should be an error
function f<T extends number>(p: number)
function f<T extends number>(p: string) // should be an error
function f<T extends number>(p: I) // should be an error
function f<T extends number>(p: T) { }

Activity

  1. mhegazy commented on Mar 3, 2016

    @mhegazy
    Contributor

    sounds like a fair check to add.

  2. DanielRosenwasser commented on Mar 3, 2016

    @DanielRosenwasser
    Member

    I think that this would be a good change, but it would make implementation/overload assignability diverge further from standard assignability rules on signatures.

    From 3.11.4 in the spec:

    [A type] S is _assignable to_ a type T, and T is _assignable from_ S, if S has no excess properties with respect to T (3.11.5) and one of the following is true:

    • S is an object type, an intersection type, an enum type, or the Number, Boolean, or String primitive type, T is an object type, and for each member M in T, one of the following is true:
      • M is a non-specialized call or construct signature and S has an apparent call or construct signature N where, when M and N are instantiated using type Any as the type argument for all type parameters declared by M and N (if any),

    The important part is "are instantiated using type Any as the type argument for all type parameters". We look for the "erased" versions of each function.

    This is not to say we couldn't change the current behavior. I'd be curious to see how code is affected, but it would be a breaking change.

  3. falsandtru commented on Mar 3, 2016

    @falsandtru
    ContributorAuthor

    similar case:

    interface I {
      toString(): number;
    }
    function f(p: void) // erorr
    function f(p: number)
    function f(p: string) // erorr
    function f(p: I) // erorr
    function f(p: number) { }

    I expect a behavior that has consistency.

    function f<T extends number>(p: T) { }
    f(''); // error
    interface I {
      toString(): number;
    }
    function f<T extends number>(p: void)
    function f<T extends number>(p: number)
    function f<T extends number>(p: string)
    function f<T extends number>(p: I)
    function f<T extends number>(p: T) { }
    f(''); // ok

    Overloads shouldn't widen a range of type parameters.

    Additionally, this behavior omits a feature of non-nullable types.

  4. added
    Too ComplexAn issue which adding support for may be too complex for the value it adds
    and removed
    Breaking ChangeWould introduce errors in existing code
    on Jun 9, 2016
  5. RyanCavanaugh commented on Jun 9, 2016

    @RyanCavanaugh
    Member

    This somewhere between too complex and "not actually wrong". For example:

    function f<T extends number>(p: void)
    function f<T extends number>(p: number)
    function f<T extends number>(p: string) // <--
    function f<T extends number>(p: T) { }

    In the indicated line, T might be the type string & number, which actually satisfies the constraint. There's also no relation between all the Ts here so it's not clear what the signature is trying to say -- when T doesn't appear in the parameter list or the return type, it's totally meaningless.

    The real purpose of the overload checking is to stop people from doing this (which they still manage to do with sad regularity):

    function fn(x: string): void;
    function fn(x: number) { }
    fn(42); // Not OK, wat??

    Outside of detecting the "I thought I had two signatures" case, we generally consider you to be "on your own" in terms of writing an implementation signature that is plausibly correct.

  6. 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