Skip to content
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

private property lost context in `Promise.finally()` when using arrow function #9970

Open
piranna opened this issue May 13, 2019 · 2 comments

Comments

Projects
None yet
3 participants
@piranna
Copy link

commented May 13, 2019

Bug Report

Current Behavior
I'm setting an arrow function as resolver of a Promise.finally(). This arrow function is setting to false a private attribute in my class to indicate the Promise has finally (by instance, the private attribute host the Promise itself, I use it as a flag to know if the promised operation is running).

After transpiling with Babel, I get an error about "setting a private attribute of a not object instance". Reviewing the transpiled code, it has converted the arrow function in a regular function, loosing the this context and using global one instead, throwing that error.

Input Code

This is a reduced version of my failing code, it checks if the private attribute has a value set (the Promise object) and if so use it, if not create a new one. This way, all calls to Sample.connect() method will return and wait for the same Promise object if a connection is currently being stablished.

class Sample
{
  #connecting

  connect()
  {
    if(this.#connecting) return this.#connecting

    this.#connecting = ConnectWithPromise()
      .then(console.log, this.emit.bind(this, 'error'))
      .finally(() => this.#connecting = false)

    return this.#connecting
  }
}

Expected behavior/code
The output code should be like this, it's said, maintain the arrow function:

  connect()
  {
    const connecting = _classPrivateFieldGet(this, _connecting);

    if (connecting) return connecting;

    _classPrivateFieldSet(this, _connecting, ConnectWithPromise().then(console.log, this.emit.bind(this, 'error')).finally(() => {
      _classPrivateFieldSet(this, _connecting, false);
    }));

    return _classPrivateFieldGet(this, _connecting);
  }

but instead, it gets converted to use a regular function, like this:

  connect()
  {
    const connecting = _classPrivateFieldGet(this, _connecting);

    if (connecting) return connecting;

    _classPrivateFieldSet(this, _connecting, ConnectWithPromise().then(console.log, this.emit.bind(this, 'error')).finally(function() {
      _classPrivateFieldSet(this, _connecting, false);
    }));

    return _classPrivateFieldGet(this, _connecting);
  }

Babel Configuration (.babelrc, package.json, cli command)

module.exports = {
  plugins: [
    '@babel/plugin-transform-flow-strip-types',
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-optional-chaining',
    '@babel/plugin-proposal-private-methods'
  ],
  presets: [
    'module:metro-react-native-babel-preset',
    'module:react-native-dotenv'
  ]
}
{
  "name": "testRN",
  "version": "2.0.0-0",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "android:clean": "cd android && ./gradlew clean",
    "android:dev_menu": "adb shell input keyevent KEYCODE_MENU",
    "android:emulator": "scripts/android:emulator.js",
    "android:log": "react-native log-android",
    "android:release": "cd android && ./gradlew assembleRelease",
    "android:release:test": "npm run android -- --variant=release",
    "docs:api": "jsdoc2md --files **/*.js --global-index-format none > docs/api.md",
    "docs:build": "gitbook build",
    "docs:clean": "rimraf _book",
    "docs:serve": "gitbook serve",
    "install": "gitbook install",
    "ios": "react-native run-ios",
    "ios:release": "react-native bundle --platform=ios",
    "kill_server": "fuser -k 8081/tcp || true",
    "lint": "eslint .",
    "postdocs:api": "git add docs/api.md",
    "predocs:api": "mkdir -p docs",
    "predocs:build": "npm run docs:api",
    "predocs:serve": "npm run docs:api",
    "preandroid": "scripts/preandroid.sh",
    "preandroid:release:test": "npm run android:release",
    "prestart": "npm run kill_server",
    "pretest": "npm run lint",
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "true"
  },
  "dependencies": {
    "@lingbe/client-core": "github:lingbeapp/client-core",
    "@lingbe/react-native-base-components": "github:lingbeapp/react-native-base-components",
    "@redux-offline/redux-offline": "^2.5.1",
    "es6-symbol": "^3.1.1",
    "i18n-js": "^3.2.1",
    "max-timeout": "^1.0.0",
    "moment": "^2.24.0",
    "node-libs-react-native": "^1.0.3",
    "react": "16.8.6",
    "react-native": "^0.59.8",
    "react-native-animatable": "^1.3.2",
    "react-native-check-box": "^2.1.7",
    "react-native-date-picker": "^2.3.0",
    "react-native-device-info": "^1.4.3",
    "react-native-dotenv": "^0.2.0",
    "react-native-gesture-handler": "^1.1.0",
    "react-native-gifted-chat": "^0.7.3",
    "react-native-keyboard-aware-scroll-view": "^0.8.0",
    "react-native-parsed-text": "^0.0.21",
    "react-native-responsive-ui": "^1.1.1",
    "react-native-safe-area": "^0.5.0",
    "react-native-splash-screen": "^3.2.0",
    "react-native-vector-icons": "^6.4.2",
    "react-native-webrtc": "^1.69.1",
    "react-navigation": "^3.8.1",
    "react-redux": "^6.0.1",
    "redux": "^4.0.1",
    "socket.io-client": "^2.0.4",
    "vm-browserify": "^1.1.0"
  },
  "devDependencies": {
    "@babel/core": "^7.4.4",
    "@babel/plugin-proposal-class-properties": "^7.4.4",
    "@babel/plugin-proposal-optional-chaining": "^7.2.0",
    "@babel/plugin-proposal-private-methods": "^7.4.4",
    "@babel/plugin-transform-flow-strip-types": "^7.4.4",
    "@babel/preset-env": "^7.4.4",
    "babel-eslint": "^11.0.0-beta.0",
    "babel-jest": "24.7.1",
    "eslint": "^5.16.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-plugin-extra-rules": "^0.8.1",
    "eslint-plugin-import": "^2.17.2",
    "eslint-plugin-jest": "^22.5.1",
    "eslint-plugin-jsdoc": "^4.8.3",
    "eslint-plugin-json": "^1.4.0",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "eslint-plugin-node": "^8.0.1",
    "eslint-plugin-promise": "^4.1.1",
    "eslint-plugin-react": "^7.12.4",
    "eslint-plugin-sort-keys-fix": "^1.0.1",
    "eslint-plugin-standard": "^4.0.0",
    "gitbook-cli": "^2.3.2",
    "husky": "^2.1.0",
    "jest-cli": "24.7.1",
    "jsdoc-to-markdown": "^4.0.1",
    "metro-react-native-babel-preset": "0.53.1",
    "react-test-renderer": "16.8.6"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm test && npm run docs:api",
      "pre-push": "npm test"
    }
  },
  "jest": {
    "collectCoverageFrom": [
      "src/**/*.js"
    ],
    "preset": "react-native",
    "transformIgnorePatterns": [
      "node_modules/(?!(@expo/react-native-action-sheet|react-native|react-native-check-box|react-native-communications|react-native-device-info|react-native-gifted-chat|react-native-gesture-handler|react-native-iphone-x-helper|react-native-keyboard-aware-scroll-view|react-native-lightbox|react-native-parsed-text|react-native-responsive-ui|react-native-screens|react-native-video|react-navigation-stack)/)"
    ]
  },
  "rnpm": {
    "assets": [
      "./assets/fonts/"
    ]
  }
}
npm start -- --reset-cache

Environment

  • Babel version(s): 7.4.4
  • Node/npm version: Node 12.2.0 / npm 6.9.0
  • OS: Ubuntu 19.04
  • Monorepo: no
  • How you are using Babel: React Native CLI

Possible Solution
I changed by hand the regular function for an arrow function in the generated code, and it worked flawlessly.

@babel-bot

This comment has been minimized.

Copy link
Collaborator

commented May 13, 2019

Hey @piranna! We really appreciate you taking the time to report an issue. The collaborators
on this project attempt to help as many people as possible, but we're a limited number of volunteers,
so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack
community
that typically always has someone willing to help. You can sign-up here
for an invite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.