Skip to content

Intersected function type returns only first constituent's return type #10508

Closed

Description

@vsiao

TypeScript Version: 1.8/Playground

Code

interface A {
    a: boolean;
}
interface B {
    b: boolean;
}

declare const fooAB: (() => A) & (() => B);
const ab = fooAB(); // A

Expected behavior: ab has type A & B

Actual behavior: ab has type A

Perhaps this is being treated as an overloaded call signature, and () => A just happens to be first. If this is by design, it would be great to learn about any known workarounds.

cc kevinder

Activity

  1. kitsonk commented on Aug 24, 2016

    @kitsonk
    Contributor

    this is covariance, right? dupe of #1394?

  2. mhegazy commented on Aug 24, 2016

    @mhegazy
    Contributor

    (() => A) & (() => B); is not equivalant to (() => A & B);.

    (() => A) & (() => B); is equivalent to

    declare const fooAB: {
        (): A;
        (): B
    };
  3. aluanhaddad commented on Sep 4, 2016

    @aluanhaddad
    Contributor

    Mohamed Hegazy (@mhegazy) I understand that the current behavior is practical, but the only way a function could actually implement the intersection would be by returning a value of A & B. Maybe it is not realistic but since, IIRC the compiler will always pick the first overload, it would be reasonable to expect the intersection.

  4. mhegazy commented on Sep 7, 2016

    @mhegazy
    Contributor

    The compiler has no way of merging signatures in the general case. this one seems simple enough, but what happens if there are parameters involved, what if they have different count, what if one of them is generic, what if the parameter types do not agree.. for instance
    (a: number, b:string) => A and (a: string, b: number) => B is this (a: number|string, b: number|string) => A&B ? i do not think this is correct.

  5. aluanhaddad commented on Sep 7, 2016

    @aluanhaddad
    Contributor

    Mohamed Hegazy (@mhegazy) I agree that's not correct specifically because the functions have different parameter types. This means that using the union of each corresponding parameter is not accurate. Interestingly though, this also means that there is a way to select the overload that you want, so I don't think these signatures need to be merged.

    Obviously it's not a trivial problem.

    I think the intuitive behavior would be to only merge signatures when they match exactly in arity and parameter types.

    My reasoning is that there's no way to statically select and thus differentiate between the different signatures that are available without using a type assertion.

  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

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions