Parcel: static Symbol.hasInstance override fails

Created on 2 Dec 2018  路  2Comments  路  Source: parcel-bundler/parcel

馃悰 bug report

_Appears_ to bundle a class with Symbol.hasInstance override improperly.

export default class CoolClass
{
    constructor()
    {
        this.name = 'CoolClass';
    }

    // works just fine
    static method()
    {
        return 'hello';
    }

    // When this method is present, the browser says "Cannot call a class as a function"
    static [ Symbol.hasInstance ]( instance )
    {
        return instance.name === 'CoolClass';
    }
}

馃帥 Configuration (.babelrc, package.json, cli command)

.babelrc

{
    "presets": [
        [ "@babel/preset-env" ]
    ]
}

package.json

{
    "name": "ui",
    "version": "1.0.0",
    "description": "",
    "main": "",
    "scripts": {
        "build": "parcel build app/index.html --out-dir build",
        "dev": "parcel watch app/index.html --out-dir build",
        "start": "parcel app/index.html --out-dir build --target browser",
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
        "@babel/polyfill": "7.0.0",
        "@fortawesome/fontawesome-free": "5.5.0",
        "bootstrap": "4.1.3",
        "hyperapp": "1.2.9"
    },
    "devDependencies": {
        "@babel/core": "7.1.6",
        "@babel/preset-env": "7.1.6",
        "chai": "^4.1.2",
        "chai-as-promised": "^7.1.1",
        "eslint": "^5.1.0",
        "jsdoc-to-markdown": "^4.0.1",
        "mocha": "^5.2.0",
        "parcel-bundler": "1.10.3",
        "sass": "1.15.1"
    }
}

cli command: npm start

馃 Expected Behavior

import CoolClass from './CoolClass';

const
    item = new CoolClass(),
    obj   = new Object();

console.log( item instanceof CoolClass ); // true
console.log( obj instanceof CoolClass ); // false

馃槸 Current Behavior

Toolbar.js: 9 is where I import the class with static [ Symbol.hasInstance ]( instance )
(import CoolClass from './CoolClass';)

Stack Trace:

Uncaught TypeError: Cannot call a class as a function
at _classCallCheck (Toolbar.js:9)
at new Toolbar (Toolbar.js:14)
at view (global.js:23)
at resolveNode (index.js:57)
at render (index.js:66)
_classCallCheck @   Toolbar.js:9
Toolbar @   Toolbar.js:14
view    @   global.js:23
resolveNode @   index.js:57
render  @   index.js:66
setTimeout (async)
scheduleRender  @   index.js:80
app @   index.js:39
parcelRequire.js/global.js.hyperapp @   global.js:49
newRequire  @   js.00a46daa.js:49
hmrAccept   @   index.js:11
(anonymous) @   index.js:11
hmrAccept   @   index.js:11
(anonymous) @   index.js:11
hmrAccept   @   index.js:11
(anonymous) @   index.js:11
ws.onmessage    @   index.js:11

馃拋 Possible Solution

A quick search of Symbol turns up this file

And particularly this method

But it appears to be searching other references for Symbol's.

馃敠 Context

Overriding static and non-static symbol methods is a common practice. It would be nice to continue that practice.

Other static and non-static Symbol overrides work:
Non-static [ Symbol.toPrimitive ]( n ) (works fine)
get Non-static get [ Symbol.toStringTag ]() (works fine)
get static static get [ Symbol.species ]() (works fine)
static static method() (works fine)
static static [ Symbol.hasInstance ]( instance ) (error results above)

馃捇 Code Sample


(See above)

馃實 Your Environment

| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | v1.10.3
| Node | v10.13.0
| npm/Yarn | v6.4.1
| Operating System | macOS Mojave 10.14.1 (18B75)

(uname -a)

Darwin MacBook-Pro.local 18.2.0 Darwin Kernel Version 18.2.0: Fri Oct  5 19:41:49 PDT 2018; root:xnu-4903.221.2~2/RELEASE_X86_64 x86_64
Bug

Most helpful comment

Yup - this is an issue with Babel.

_Although_, wouldn't this be a bug with Babel?

Symbol.hasInstance is an ECMAScript standard ECMA-262 6th Edition 19.4.2.2

Shouldn't Babel allow this "well known symbol"?

All 2 comments

@iSkore,

Let's look at what happens, babel transform the code to roughly:

var CoolClass =
/*#__PURE__*/
function () {
  function CoolClass() {
    _classCallCheck(this, CoolClass);

    this.name = 'CoolClass';
  }

  _createClass(CoolClass, null, [{
    key: Symbol.hasInstance,
    value: function value(instance) {
      return instance.name === 'CoolClass';
    }
  }]);

  return CoolClass;
}();

with 

function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

So, _classCallCheck is being invoked before this.name = CoolClass in the constructor takes place. At this point, instanceof returns false even for instances of the correct class instead of true. At this point, babel assumes that we have called CoolClass as a function instead of the new operator since instanceof returns misleadingly false.

Point being: I don't think this is a bug in either babel or parcel, but simply how babel works. Maybe the best approach here is to brainstorm another solution for the use case, maybe write your own method hasInstanceOf?

I think this issue could be closed as it's not actionable from parcel's viewpoint, but happy to brainstorm about another solution with @iSkore.

Yup - this is an issue with Babel.

_Although_, wouldn't this be a bug with Babel?

Symbol.hasInstance is an ECMAScript standard ECMA-262 6th Edition 19.4.2.2

Shouldn't Babel allow this "well known symbol"?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

466023746 picture 466023746  路  3Comments

devongovett picture devongovett  路  3Comments

jsftw86 picture jsftw86  路  3Comments

philipodev picture philipodev  路  3Comments

jzimmek picture jzimmek  路  3Comments