Typescript: Fail to import `classPrivateFieldGet` from tslib when `"importHelpers": true`

Created on 17 Feb 2020  路  15Comments  路  Source: microsoft/TypeScript

I am testing out the lastest ECMA private fields. I get an error when importHelpers enabled:

This syntax requires an imported helper named '__classPrivateFieldGet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.ts(2343)

I'm not sure if there's pending work on the tslib, so I'm repoting this anyway.


TypeScript Version: 3.8.1-rc
TS Lib Version: 1.1.0


Search Terms:
tslib classPrivateFieldGet

Code

class A {
    #a: number

    constructor() {
        this.#a = 1
    }
}


Expected behavior:

This should compile

Actual behavior:

Shows an error on tslib

Playground Link:

Related Issues:

Fix Available Needs Investigation Rescheduled

Most helpful comment

Same issue with TS 3.9.3 and tslib 2.0.0

All 15 comments

I have a few additional observations:

  1. When I only compile one file typescript seems to completely ignore the importHelpers: true option and emit all required helpers (including __classPrivateFieldGet and __classPrivateFieldSet) into the js file. When the compiled file references other files via imports the behaviour @pirix-gh described occurres.
  2. When module: "CommonJS" is set, it imports all helpers just as you would expect. However, when module: "ESNext" or "module: "ES2015" it does not import __classPrivateFieldGet and __classPrivateFieldSet (other helpers like __awaiter are imported though)

I believe that this is a bug as the helpers for setting and getting private fields will be imported only when module set to CommonJS.

i have another question. ts transplie #property to weakmap(this) to store the property value.

while the class instance destroyed and recycled by the gc, the property value of this class instance still store in weakmap.

will it cause a memory leak?

well, reply to myself, it seems chrome will clean up all values in weakmap after their key have been gc'ed

@duxiaofeng-github Not just chome, but v8 in general and all other javascript engines too. It is a part of the specification as you can read here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap

@Haringat thx, i read that doc before, i must miss something...

Same issue here with typescript 3.8.3 and tslib 1.11.1.

Same issue with TS 3.9.3 and tslib 2.0.0

With Typescript 3.8.2 (also applies with TS 3.9.3) and tslib 2.0.0, I have got a runtime Error ReferenceError: __classPrivateFieldGet is not defined

Experiencing a similar issue with typescript 3.8.3 and tslib 1.11.1, where a runtime error occurs Can't find variable: __classPrivateFieldSet.

Truncated tsconfig.json:

{
  "compilerOptions": {
    "importHelpers": true,
    "target": "ES2017",
    "jsx": "react",
    "module": "CommonJS",
    "resolveJsonModule": true,
    "lib": ["dom", "dom.iterable", "es2015", "es2016", "es2017"],
    "esModuleInterop": true,
    "allowJs": true,
    "strict": true,
    "downlevelIteration": true,
    "plugins": [
      {
        "transform": "typescript-is/lib/transform-inline/transformer",
        "shortCircuit": false,
        "ignoreClasses": true,
        "ignoreMethods": true,
        "ignoreFunctions": true,
        "disallowSuperfluousObjectProperties": false
      }
    ],
    "moduleResolution": "node",
    "isolatedModules": true
  }
}

I cannot seem to repro this with typescript@next and [email protected]

@Haringat: --importHelpers will not be used if the TypeScript thinks the file is a Script rather than a Module. Even with --module commonjs, if there are no imports or exports in the file it considers it to be a global script. If you want it to use tslib, you need to ensure there is at least one import or export to indicate it is a module, even if that is an empty export (i.e., export {};)

I believe the type error in the original description was fixed at some point between when the issue was filed and now. Its possible the runtime issue may have been addressed by another PR in the meantime, as well, as there have been several recent PRs that could affect tslib import. If anyone is still experiencing an issue and can provide a consistent repro using typescript@beta and [email protected] please let me know and I will look into this again.

@rbuckton
I experienced the same problem, both typescript@beta and typescript@next.

Repo: https://github.com/toyobayashi/import-helpers-private-field-issue

package.json

{
  // ...
  "scripts": {
    "build": "tsc && tsc -p ./tsconfig.cjs.json"
  },
  "devDependencies": {
    "tslib": "^2.0.0",
    "typescript": "^4.0.0-beta"
  }
}

tsconfig.json & tsconfig.cjs.json

{
  "compilerOptions": {
    "outDir": "out-esm",
    "module": "ESNext",
    "target": "es2015",
    "importHelpers": true,
    "moduleResolution": "node",
  },
  "include": [
    "src/index.ts"
  ]
}

``` json
{
"compilerOptions": {
"outDir": "out-cjs",
"module": "commonjs",
"target": "es2015",
"importHelpers": true,
"moduleResolution": "node",
},
"include": [
"src/index.ts"
]
}

src/index.ts
``` ts
class A {}

class B extends A {
  #x: number = 1

  getX (): number {
    return this.#x
  }

  setX (v: number): void {
    this.#x = v
  }

  async asyncMethod (): Promise<number> {
    return 0
  }
}

export { B }

out-esm/index.js

var _x;
import { __awaiter } from "tslib"; // <-- missing __classPrivateFieldGet and __classPrivateFieldSet
class A {
}
class B extends A {
    constructor() {
        super(...arguments);
        _x.set(this, 1);
    }
    getX() {
        return __classPrivateFieldGet(this, _x); // <-- error
    }
    setX(v) {
        __classPrivateFieldSet(this, _x, v); // <-- error
    }
    asyncMethod() {
        return __awaiter(this, void 0, void 0, function* () {
            return 0;
        });
    }
}
_x = new WeakMap();
export { B };

But commonjs output correctly:

out-cjs/index.js

"use strict";
var _x;
Object.defineProperty(exports, "__esModule", { value: true });
exports.B = void 0;
const tslib_1 = require("tslib");
class A {
}
class B extends A {
    constructor() {
        super(...arguments);
        _x.set(this, 1);
    }
    getX() {
        return tslib_1.__classPrivateFieldGet(this, _x); // <-- ok
    }
    setX(v) {
        tslib_1.__classPrivateFieldSet(this, _x, v); // <-- ok
    }
    asyncMethod() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return 0;
        });
    }
}
exports.B = B;
_x = new WeakMap();

If remove async asyncMethod(), esm output will emit helpers:

var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return privateMap.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to set private field on non-instance");
    }
    privateMap.set(receiver, value);
    return value;
};
var _x;
class A {
}
class B extends A {
    constructor() {
        super(...arguments);
        _x.set(this, 1);
        // async asyncMethod (): Promise<number> {
        //   return 0
        // }
    }
    getX() {
        return __classPrivateFieldGet(this, _x);
    }
    setX(v) {
        __classPrivateFieldSet(this, _x, v);
    }
}
_x = new WeakMap();
export { B };

I'll take another look, thanks for the repro

Was this page helpful?
0 / 5 - 0 ratings