Skip to content

Wrong type narrowing when types are compatibles #11664

Description

TypeScript Version: 2.0.3

Code

class Result1 {
    readonly value1: number;

    constructor(value1: number) {
        this.value1 = value1;
    }
}

class Result2 {
    readonly value1: number;
    readonly value2: number;

    constructor(value1: number, value2: number) {
        this.value1 = value1;
        this.value2 = value2;
    }
}

function someFunction(result: Result1 | Result2) {
    if (result instanceof Result1) {
        // result is still Result1 | Result2
        console.log("1");
    }
    else {
        // result is never ! this is wrong !
        console.log("2");
    }
}

// this will output 2 !
someFunction(new Result2(9,9))

Expected behavior:
instance of type guard should not care about type compatibility
Actual behavior:
Wrong assertion by the compiler.

Activity

  1. yortus commented on Oct 16, 2016

    @yortus
    Contributor

    Essentially a duplicate of #10934. See also design notes about instanceof in #8503.

  2. akarzazi commented on Oct 16, 2016

    @akarzazi
    Author

    Indeed, this is a duplicate :(
    From #7271, the issue will be fixed in 2.1.

  3. yortus commented on Oct 16, 2016

    @yortus
    Contributor

    Adel KARZAZI (@akarzazi) note that the fix for #7271 only affects narrowing structurally identical types, but your issue here (like #10934) is with narrowing structural subtype/supertypes. This hasn't been solved yet and is on the roadmap for future investigation at an unspecified time.

  4. akarzazi commented on Oct 16, 2016

    @akarzazi
    Author

    Troy Gerwien (@yortus) I thought the fix will cover type compatibly as well.
    Since mhegazy said : As noted in #8503, classes should be treated definitely for instanceof checks.

  5. mikelehen commented on May 4, 2017

    @mikelehen

    FYI- This still reproduces with TypeScript 2.3.2

  6. nodefish commented on Jun 21, 2017

    @nodefish

    Really simplistic example of what's wrong with instanceof:

    const model = this.opts.resources.model.store.get(id);
    if (!model || model instanceof Placeholder)
        return null;
    const data: any = model.get();

    TSC gives the following error:
    Property 'get' does not exist on type 'never'.

    A workaround was proposed in #13325 but I can't see an equivalent in imperative code sections.

  7. added
    DuplicateAn existing issue was already created
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Nov 17, 2017
  8. RyanCavanaugh commented on Nov 17, 2017

    @RyanCavanaugh
    Member

    Fixed in #19671

  9. added
    FixedA PR has been merged for this issue
    and removed
    DuplicateAn existing issue was already created
    on Nov 20, 2017
  10. 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

    FixedA PR has been merged for this issue

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions