Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
thammi opened this issue Apr 2, 2019 · 5 comments
Closed

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

thammi opened this issue Apr 2, 2019 · 5 comments
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@thammi
Copy link

thammi commented Apr 2, 2019

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

@RyanCavanaugh
Copy link
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.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Apr 2, 2019
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 3.6.0 milestone Apr 2, 2019
@RyanCavanaugh
Copy link
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... 😕

@weswigham
Copy link
Member

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

@RyanCavanaugh
Copy link
Member

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

@weswigham
Copy link
Member

weswigham commented Oct 29, 2019

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

No branches or pull requests

4 participants