-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Corrected ES5 for-in destructuring binding emit #33337
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
Corrected ES5 for-in destructuring binding emit #33337
Conversation
Although it's not permitted in the checker to use an array or object binding pattern ("destructuring") as the iterating variable in a `for..in` loop, TypeScript can still output the syntax. This corrects the emitter to correctly destructure the variables in the body of the loop. Previously they were incorrectly being bound in the iteration statement. I'm not particularly satisfied with how this code shaped up. There's some duplication in the `convertForInStatementForLoop*` functions, but just small enough of it that I didn't extract into a shared function... does anyone see a cleaner approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have an issue with these changes in general, but one of the reasons this is an error is that we don't correctly downlevel iterator destructuring for strings in ES5, as an ES2015 string iterator yields "code points" rather than "code units", so there would be differences in runtime behavior for ES2015 and ES5 for these two emits:
// --target ES2015
for (var [a, b] in { "🐛": 1 }) console.log(a, b);
// prints: 🐛 undefined
// --target ES5
for (var _a in { "🐛": 1 }) {
var a = _a[0], b = _a[1];
console.log(a, b);
}
// prints: � �
I can bring this up in a design meeting, but I'm somewhat wary of introducing a change that:
- Only affects code we've labeled as an error
- Produces incorrect results for unicode surrogate pairs.
} | ||
|
||
function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) { | ||
function convertForStatementHead(node: ForInStatement | ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function convertForStatementHead(node: ForInStatement | ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) { | |
function convertForInOrForOfStatementHead(node: ForInStatement | ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) { |
Only because a for
statement is different from a for-in
or for-of
statement and its better to avoid confusion.
@@ -2433,6 +2445,77 @@ namespace ts { | |||
); | |||
} | |||
|
|||
function convertForInStatementForLoopDirectly(node: ForInStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[]): Statement { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could possibly simplify this by using a 3rd function that optionally converts the iteration statement, or make the conversion function something that is passed in as an argument (and falls back to visitEachChild(node, visitor, context)
when not converting).
We discussed this in the design meeting today, and while we appreciate the effort that went into putting together this PR, unfortunately we will not be taking this change. There are several factors involved:
However, since this is legal ES2015, we may consider removing the error for |
Although it's not permitted in the checker to use an array or object binding pattern ("destructuring") as the iterating variable in a
for..in
loop, TypeScript can still output the syntax. This corrects the emitter to correctly destructure the variables in the body of the loop. Previously they were incorrectly being bound in the iteration statement.I'm not particularly satisfied with how this code shaped up. There's some duplication in the
convertForInStatementForLoop*
functions, but just small enough of it that I didn't extract into a shared function... does anyone see a cleaner approach?Fixes #2272