Skip to content

A union including non-iterable types is not iterable #40350

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

Merged
merged 3 commits into from
Sep 11, 2020

Conversation

andrewbranch
Copy link
Member

@andrewbranch andrewbranch commented Sep 1, 2020

See discussion inline.

Fixes #35497.

@typescript-bot typescript-bot added Author: Team For Milestone Bug PRs that fix a bug with a specific milestone labels Sep 1, 2020
@andrewbranch andrewbranch marked this pull request as draft September 1, 2020 23:32

const a = yield 0;
>a : 1
>yield 0 : 1
>a : 1 | undefined
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a sense, this is not wrong—gen could have its next() called with no arguments, making a undefined at runtime. But previously, this fell into a special case of ignoring that optionality for convenience.

Now, when we try to get the iteration types of Generator<R, T, S> | AsyncGenerator<R, T, S> as an async iterable, we get noIterationTypes, because the former doesn’t have a [Symbol.asyncIterator]() member. Instead, we fall back to getting the iteration types of this union as an async iterator, using its next/return/throw method signatures to determine T, TReturn, and TNext. Because we have a union signature, it doesn’t count as a reference to one of the global generator/iterator types, and so it doesn’t take the fast path that ignores the optionality. Instead, it correctly sees that the next() method can take no arguments or [1], and so it infers the type 1 | undefined.

More work could be done to make union signatures take the fast path that drops the optionality if every signature in the union is a reference to one of the global generator/iterator types, but I felt like this was getting fairly complex for limited utility—the results it produces with less complexity are strictly more correct given the limitations we have for modeling this.

@@ -33444,8 +33444,9 @@ namespace ts {
if (iterationTypes === noIterationTypes) {
if (errorNode) {
reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag));
errorNode = undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I kept looping was to provide some kind of useful type for iteration once they fixed the error. The problem the issue mentioned was that no error was reported.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(btw: I'm not saying this change is wrong, just expressing the reasoning behind the existing logic).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that makes sense in theory, but the problem here was that errorNode was intentionally not supplied, so the non-iterableness of the type was completely lost.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about the baseline change?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems fine. I do wonder about the | null case. If it were data[Symbol.iterator]() we would have errored on data with Object is possibly 'null'..

@andrewbranch andrewbranch marked this pull request as ready for review September 10, 2020 15:58
@sandersn sandersn assigned rbuckton and unassigned andrewbranch Sep 10, 2020
@rbuckton
Copy link
Contributor

This also seems to have fixed #34956.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Milestone Bug PRs that fix a bug with a specific milestone
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Destructuring possible null value with --downlevelIteration and any ES --lib ignores errors
3 participants