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

Generators with extended unions, null and undefined produces compiler errors #40044

Open
LeviticusMB opened this issue Aug 14, 2020 · 1 comment
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@LeviticusMB
Copy link

I've run into a weird problem in a project that uses async generators. I've reduced the problematic code to the example
below, which also fails in a similar way that my actual code does.

There seem to be several conditions that must be fulfilled:

  1. Type T is a union.
  2. The argument generator extends T (with WithID in the example).
  3. The argument generator also accepts both null and undefiened.
  4. The provided generator has a return signature.
  5. The provided generator's return signature yields T and either null or undefined (but not both).

Change just any of these conditions in the playground, and the error goes away ...

TypeScript Version: 4.0.0-beta (and below)

Search Terms: generator null undefined

Expected behavior: No errors.

Actual behavior: A strange error message when doSomething() is called.

Related Issues: No

Code

interface WithID {
    id?: number;
}

type MyEvent = { type: "number", value: number } |  { type: "string", value: string };
//interface MyEvent { type: "number" | "string", value: number | string };

function doSomething<T extends object>(gen: Generator<T & WithID | undefined | null>) {
    // ...
}

function* readEvents(): Generator<MyEvent | undefined> {
    yield undefined;
}

doSomething(readEvents());
Output
"use strict";
//interface MyEvent { type: "number" | "string", value: number | string };
function doSomething(gen) {
    // ...
}
function* readEvents() {
    yield undefined;
}
doSomething(readEvents());
Compiler Options
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": 2,
    "target": "ES2019",
    "jsx": "React",
    "module": "ESNext"
  }
}

Playground Link: Provided

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Sep 3, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.1.0 milestone Sep 3, 2020
@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Dec 11, 2020
@rbuckton
Copy link
Member

The error may stem from doSomething inferring the wrong type for T, as doSomething(readEvents()) seems to infer T to { type: "number"; value: number; } and not MyEvent. The error also goes away if you write doSomething<MyEvent>(readEvents()); instead. I will need to investigate further to determine if this is something we can improve on.

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. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

No branches or pull requests

4 participants