Skip to content

Method returning index type breaks type interference of union types #30717

Closed

Description

@thammi

TypeScript Version: 3.4.0-dev.201xxxxx

Search Terms: union, index type

Code

class Test<Props extends Object> {
  constructor(public o: Props) {}
  get<K extends keyof Props>(k: K) : Props[K] { return this.o[k]; }
}

interface A {t: "A";};
interface B {t: "B";};
type u = Test<A> | Test<B>;

const tmp = new Test<B>({t: 'B'}) as u;

switch(tmp.get('t')) {
  case 'A': break;
  case 'B': break;
}

Expected behavior:

Code compiles with tmp.get('t') having type "A" | "B".

This works for:

Actual behavior:

Compilation fails with error:

Type '"B"' is not comparable to type '"A"'.

Type of tmp.get('t') is only "A".

Problem is not contained to string literals, but also other types. Enountered this bug using immutable-js Record.get().

Playground Link: playground

Related Issues: None found

Activity

  1. RyanCavanaugh commented on Apr 2, 2019

    @RyanCavanaugh
    Member

    Simplified very slightly

    declare class Test<T> {
      obj: T;
      get<K extends keyof T>(k: K): T[K];
    }
    
    interface A { t: "A" }
    interface B { t: "B" }
    
    declare const tmp: Test<A> | Test<B>;
    
    switch(tmp.get('t')) {
      case 'A': break;
      case 'B': break;
    }

    Not a regression - this has been the behavior since 2.1.

  2. RyanCavanaugh commented on Apr 2, 2019

    @RyanCavanaugh
    Member

    We don't even understand why the tmp.get call was allowed in the first place? Generic signatures should not have unified across union type boundaries... 😕

  3. weswigham commented on Jul 15, 2019

    @weswigham
    Member

    I have a PR open here, but IIRC a recent change anders made should have also fixed this - I'll check.

  4. RyanCavanaugh commented on Oct 29, 2019

    @RyanCavanaugh
    Member

    This now works the way we want it to - the call to get is flagged as an error.

  5. weswigham commented on Oct 29, 2019

    @weswigham
    Member

    Ryan Cavanaugh (@RyanCavanaugh) there is some additional code in #31023 that makes the call not-an-error, as the type parameters and argument lists in use are identical, so unifying them isn't so bad.

  6. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions