Skip to content

Weird inference bug where a union is expanded with "never" in the position of generics #31081

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

Open
calebmer opened this issue Apr 24, 2019 · 0 comments
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status.

Comments

@calebmer
Copy link

calebmer commented Apr 24, 2019

TypeScript Version: 3.5.0-dev.20190423

This code works in 3.3.4000 and is broken in 3.4.5

Code

function MyComponent({a, b}: {a: number; b: number}) {
  return a + b;
}

function test<Props>(
  _getComponent: () => Promise<(props: Props) => number | string>,
) {}

test(() => Promise.resolve({MyComponent}).then(m => m.MyComponent));

Of course this is a simplified example. The code I found this in uses React and lazy loading with import().

Expected behavior: This example should pass type checking without any problems.

Actual behavior:

test.ts:9:12 - error TS2322: Type 'Promise<(({ a, b }: { a: number; b: number; }) => number) | ((props: never) => string | number)>' is not assignable to type 'Promise<(props: { a: number; b: number; }) => string | number>'.
  Type '(({ a, b }: { a: number; b: number; }) => number) | ((props: never) => string | number)' is not assignable to type '(props: { a: number; b: number; }) => string | number'.
    Type '(props: never) => string | number' is not assignable to type '(props: { a: number; b: number; }) => string | number'.
      Types of parameters 'props' and 'props' are incompatible.
        Type '{ a: number; b: number; }' is not assignable to type 'never'.

9 test(() => Promise.resolve({MyComponent}).then(m => m.MyComponent));
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  test.ts:6:18
    6   _getComponent: () => Promise<(props: Props) => number | string>,
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The expected type comes from the return type of this signature.

Notably here the actual type is inferred to be…

Promise<(({ a, b }: { a: number; b: number; }) => number) | ((props: never) => string | number)>

…which has an extra union variant…

(props: never) => string | number

…coming out of nowhere.

Playground Link:

You need to enable strictFunctionTypes.

http://www.typescriptlang.org/play/index.html#src=function%20MyComponent(%7Ba%2C%20b%7D%3A%20%7Ba%3A%20number%3B%20b%3A%20number%7D)%20%7B%0A%20%20return%20a%20%2B%20b%3B%0A%7D%0A%0Afunction%20test%3CProps%3E(%0A%20%20_getComponent%3A%20()%20%3D%3E%20Promise%3C(props%3A%20Props)%20%3D%3E%20number%20%7C%20string%3E%2C%0A)%20%7B%7D%0A%0Atest(()%20%3D%3E%20Promise.resolve(%7BMyComponent%7D).then(m%20%3D%3E%20m.MyComponent))%3B%0A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

No branches or pull requests

3 participants