Skip to content

"arguments" incorrectly munged to "arguments_1" in numerous circumstances in a for loop targeting ES5 #38594

@Taytay

Description

@Taytay

TypeScript Version: Nightly (also, 3.9.2, 3.7.4, and probably others)

Search Terms:
arguments property, arguments_1 renamed

Expected behavior:
When targeting ES5, an object declared like so:
{arguments: "foo"}
is emitted to javascript as:
{arguments: "foo"}

Actual behavior:
The object is emitted to javascript as:
{arguments_1: "foo"}

See below code sample for more related bugs.

Related Issues:

A similar variant was reported and correctly fixed here:
#13586

This exact bug was previously reported here, and closed as "fixed" by the reporter. (I don't think it was actually fixed though).
#33540

Code

// Compile with ES5 target
function myFunc(_param: string) {
    for (let x = 0; x < 1; ++x){
        let i : number;
        // It's essential to have an inner function declared that references a variable defined in the loop
        [].forEach(function () { i })

        let brokenObj1 = {
            arguments: 0
        }
        // Actual:   {"arguments_1":0}
        // Expected: {"arguments":0}
        console.log(JSON.stringify(brokenObj1)); 

        let brokenObj2 = {
            arguments
        }
        // Actual:   {"arguments":{"0":0}}
        // Expected: {"arguments":{"0":"paramValue"}}
        // (Becuase it erroneously references the arguments of the generated loop function `_loop_1`)
        console.log(JSON.stringify(brokenObj2)); 
        

        let brokenObj3 = {
            arguments: arguments
        }
        // Actual:   {"arguments_1":{"0":"paramValue"}}
        // Expected: {"arguments":{"0":"paramValue"}}
        console.log(JSON.stringify(brokenObj3)); 
    }
}

myFunc("paramValue");
Output
"use strict";
// Compile with ES5 target
function myFunc(_param) {
    var _loop_1 = function (x) {
        var i;
        // It's essential to have an inner function declared that references a variable defined in the loop
        [].forEach(function () { i; });
        var brokenObj1 = {
            arguments_1: 0
        };
        // Actual:   {"arguments_1":0}
        // Expected: {"arguments":0}
        console.log(JSON.stringify(brokenObj1));
        var brokenObj2 = {
            arguments: arguments
        };
        // Actual:   {"arguments":{"0":0}}
        // Expected: {"arguments":{"0":"paramValue"}}
        // (Becuase it erroneously references the arguments of the generated loop function `_loop_1`)
        console.log(JSON.stringify(brokenObj2));
        var brokenObj3 = {
            arguments_1: arguments_1
        };
        // Actual:   {"arguments_1":{"0":"paramValue"}}
        // Expected: {"arguments":{"0":"paramValue"}}
        console.log(JSON.stringify(brokenObj3));
    };
    var arguments_1 = arguments;
    for (var x = 0; x < 1; ++x) {
        _loop_1(x);
    }
}
myFunc("paramValue");
Compiler Options
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "useDefineForClassFields": false,
    "alwaysStrict": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "downlevelIteration": false,
    "noEmitHelpers": false,
    "noLib": false,
    "noStrictGenericChecks": false,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "esModuleInterop": true,
    "preserveConstEnums": false,
    "removeComments": false,
    "skipLibCheck": false,
    "checkJs": false,
    "allowJs": false,
    "declaration": true,
    "experimentalDecorators": false,
    "emitDecoratorMetadata": false,
    "target": "ES2017",
    "module": "ESNext"
  }
}

Playground Link: Provided

P.S. Typescript is awesome. We ❤️Typescript!

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions