Skip to content

Bug in type compatibility of call signature parameters? #2170

Closed
@sccolbert

Description

@sccolbert

I'm confused why the spec (section 3.10.4) allows this situation:

interface IFoo {
    a: number;
}

interface IBar extends IFoo {
    b: string;
}

function expectsBar(bar: IBar): void {
    console.log(bar.b);
}

function providesFoo(cb: (arg: IFoo) => void): void {
    cb({ a: 1 });
}

function providesBar(cb: (arg: IBar) => void): void {
    providesFoo(cb); // should this be an error?
}

providesBar(expectsBar);

I would expect the indicated line to be an error, because providesFoo will pass an IFoo to a callback expecting IBar, and IFoo is not assignable to IBar.

The relevant spec language (emphasis mine):

S is assignable to a type T, and T is assignable from S, if one of the following is true:

  • S is an object type, a type parameter, 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 signatures are of the same kind (call or construct),
      • M has a rest parameter or the number of non-optional parameters in N is less
        than or equal to the total number of parameters in M,
      • for parameter positions that are present in both signatures, each parameter type
        in N is assignable to or from the corresponding parameter type in M
        , and
      • the result type of M is Void, or the result type of N is assignable to that of M

In this example N = (arg: IBar) => void and M = (arg: IFoo) => void, so the behavior is correct according to the spec because IBar is assignable to IFoo, but that's not what actually happening in this case, where an IFoo is being assigned to an IBar. Is this a bug in the spec?

Activity

danquirk

danquirk commented on Feb 28, 2015

@danquirk
Member

This is an intentional type hole to support a variety of common, existing JavaScript patterns. See https://github.com/Microsoft/TypeScript/wiki/Type%20Compatibility#function-argument-bivariance

added
By DesignDeprecated - use "Working as Intended" or "Design Limitation" instead
on Feb 28, 2015
locked and limited conversation to collaborators on Jun 18, 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

    By DesignDeprecated - use "Working as Intended" or "Design Limitation" instead

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @sccolbert@danquirk

        Issue actions

          Bug in type compatibility of call signature parameters? · Issue #2170 · microsoft/TypeScript