镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Bug: Control flow type analysis regression. #11153

Closed

Description

TypeScript Version: 2.0.3

This code compiles in TS 1.8 but not in 2.0.3
Code

class A { }
class B { constructor(public b: number) {} }

function foo(x: A | B): number | boolean {
    if (x instanceof A) { return true; }
    else if (x instanceof B) { return x.b; }
    //                                  ^ Property 'b' does not exist on type 'never'.
};

This error only appears if class A has no fields or methods,
if I add a field or a method the error disappears (but not constructor).

Activity

  1. ahejlsberg commented on Sep 26, 2016

    @ahejlsberg
    Member

    This is working as intended. The problem here is that structurally A and B are the same type (because constructors don't affect the instance type). So, the x instanceof A check also eliminates B. As you mention, it will behave correctly as long as there is some structural difference between A and B, so that is the workaround.

    That said, this is not the first time someone has reported this issue. In the particular case of instanceof it would be nice to somehow treat A and B nominally as that would more accurately reflect what happens a run-time.

  2. vagarenko commented on Sep 26, 2016

    @vagarenko
    Author

    Anders Hejlsberg (@ahejlsberg)
    I don't understand. How can they be structually identical if type B has field b: number and type A has none?

    Why then this code compiles fine:

    class A { constructor(public b: number) {} }
    class B { constructor(public b: number) {} }
    
    function foo(x: A | B): number | boolean {
        if (x instanceof A) { return true; }
        else if (x instanceof B) { return x.b; }
    };

    ?
    There is no structual difference between A and B here.

    Also, as I said this worked fine in Typescript 1.8 and it isn't mentioned in Breaking Changes page.

  3. added
    Design LimitationConstraints of the existing architecture prevent this from being fixed
    and removed
    Working as IntendedThe behavior described is the intended behavior; this is not a bug
    on Sep 26, 2016
  4. ahejlsberg commented on Sep 28, 2016

    @ahejlsberg
    Member

    Sorry, I missed the public modifier in the constructor in your first example. You're right, A and B are not structurally identical. Rather, B is a subtype of A.

    There are more details on the changes since 1.8 in #10194 and #10216. The core issue we have is that we use structural subtype relationships to reason about instanceof which isn't always correct. Specifically, it produces different results in cases where classes that don't extend each other are structurally identical or structural subtypes. We've been discussing ways to fix this but haven't yet done so.

  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

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions