Home > Back-end >  TypeScript keeps transpiling away async/await even with target: es2017
TypeScript keeps transpiling away async/await even with target: es2017

Time:08-25

Consider this test script.

#!/bin/bash -ex

rm -rf ts-async-await
mkdir ts-async-await
cd ts-async-await
npm init -y &> /dev/null
npm i --save-dev [email protected] &> /dev/null
echo "async function x() { return 1; }" > test.ts
echo '{ "compilerOptions": { "target": "es2017" } }' > tsconfig.json
npx tsc --version
npx tsc --showConfig
npx tsc test.ts
cat tsconfig.json
cat test.js

I'm creating an empty directory with a single one-liner TypeScript file, containing async/await.

async function x() { return 1; }

Then, I'm creating a tsconfig.json where the compilerOptions target is set to es2017.

{ "compilerOptions": { "target": "es2017" } }

tsc --showConfig shows:

{
    "compilerOptions": {
        "target": "es2017"
    },
    "files": [
        "./test.ts"
    ]
}

Then, I'm transpiling my test.ts file to test.js.

Expected: This one-liner should transpile cleanly to a one-liner JS file, just like it does in the TypeScript playground https://www.typescriptlang.org/play?#code/IYZwngdgxgBAZgV2gFwJYHsIwB4AoCUMA3jAE4CmyCpWAjANwwC QA

Actual: TypeScript generates 40 lines of code, downgrading my async/await code into non-async/await code with the __awaiter and __generator helpers.

How do I make my sample TypeScript project do what the playground does? Why isn't target doing the right thing for me here?

Here's the full log of the test output:

  rm -rf ts-async-await
  mkdir ts-async-await
  cd ts-async-await
  npm init -y
  npm i --save-dev [email protected]
  echo 'async function x() { return 1; }'
  echo '{ "compilerOptions": { "target": "es2017" } }'
  npx tsc --version
Version 4.7.4
  npx tsc --showConfig
{
    "compilerOptions": {
        "target": "es2017"
    },
    "files": [
        "./test.ts"
    ]
}
  npx tsc test.ts
  cat tsconfig.json
{ "compilerOptions": { "target": "es2017" } }
  cat test.js
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label  ; return { value: op[1], done: false };
                case 5: _.label  ; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
function x() {
    return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
        return [2 /*return*/, 1];
    }); });
}

CodePudding user response:

Typescript either runs as a CLI invocation on a file, or on a config that specifies the entry point, but not both (try running npx tsc test.js --p tsconfig.js and look at the output you get).

As such, this will work just fine:

> npx tsc test.ts --target esnext

and this will also work just fine:

> npx tsc

or with explicit reference to the config file:

> npx tsc --p tsconfig.json

But because you're calling npx tsc test.ts in your script, typescript is going to completely ignore your config file and just run what you told it to do purely in your CLI statement.

  • Related