Skip to content
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

3.9 regression: TS2322 error around assignment of an inferred intersection to a union #38542

Closed
RomainMuller opened this issue May 13, 2020 · 4 comments · Fixed by #38565
Closed
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@RomainMuller
Copy link

TypeScript Version: 3.9.2, 4.0.0-dev.20200512

Search Terms: TS2322, "is not assignable to type"

Code

import * as reflect from 'jsii-reflect'; // Version ^1.5.0

export type ApiElement = reflect.Type | reflect.TypeMember | reflect.EnumMember;

export interface Data {
  readonly element: ApiElement;
}

// Note: reflect.Method and reflect.Initializer both directly or indirectly implement reflect.TypeMember
export function doSomething<T extends (reflect.Method | reflect.Initializer)>(element: T): Data {
  if (reflect.Method.isMethod(element)) {
    // Type 'T & Method' is not assignable to type 'Type'.
    return { element };
  }
  if (reflect.Initializer.isInitializer(element)) {
    // Type 'T & Initializer' is not assignable to type 'Type'.
    return { element };
  }
  // Type checking absolutely fine - why'd previous ones not?
  return { element };
}

Expected behavior:
It should work like it did in TypeScript 3.8

Actual behavior:

$ tsc --build
lib/index.ts:13:14 - error TS2322: Type 'T & Method' is not assignable to type 'ApiElement'.
  Type 'T & Method' is not assignable to type 'Type'.

12     return { element };
                ~~~~~~~

  lib/index.ts:6:12
    6   readonly element: ApiElement;
                 ~~~~~~~
    The expected type comes from property 'element' which is declared here on type 'Data'

lib/index.ts:17:14 - error TS2322: Type 'T & Initializer' is not assignable to type 'ApiElement'.
  Type 'T & Initializer' is not assignable to type 'Type'.

16     return { element };
                ~~~~~~~

  lib/index.ts:6:12
    6   readonly element: ApiElement;
                 ~~~~~~~
    The expected type comes from property 'element' which is declared here on type 'Data'

Playground Link: I stored my repro at https://github.com/RomainMuller/TypeScript39-Bug (public)

Related Issues: It appears likely related to the breaking change in #37195 (but not certain)

@RomainMuller
Copy link
Author

RomainMuller commented May 13, 2020

Note - I have tried two build a reproduction that does NOT involve importing the separate package - to no avail. Maybe I just didn't try hard enough, or maybe this problem is triggering only when using a locally defined union of types from a dependency?

In any case, here are pointers to the relevant types within the jsii-reflect library (1.5.0 release):

@ahejlsberg
Copy link
Member

Simplified repro:

interface AB {
    kind: 'a' | 'b';
}

declare class CA { kind: 'a'; a: string; x: number };
declare class CB { kind: 'b'; b: string; y: number };

function bar<T extends CA | CB>(x: T & CA) {
    let ab: AB = x;  // Error, but shouldn't be
}

@RomainMuller
Copy link
Author

RomainMuller commented May 14, 2020

Oh wow so the discriminators were the problem? Swoosh! Well thanks for the prompt response & quick fix!!

@ahejlsberg
Copy link
Member

Well, the exact issue is that the new extra check in #37537 relies on empty intersections being removed (as per #36696) and that wasn't happening here.

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

Successfully merging a pull request may close this issue.

3 participants