Javascript ES6 TypeError: Class constructor Client cannot be invoked without 'new'
Asked Answered
E

11

82

I have a class written in Javascript ES6. When I try to execute nodemon command I always see this error TypeError: Class constructor Client cannot be invoked without 'new'

The full error is mentioned below:

/Users/akshaysood/Blockchain/fabricSDK/dist/application/Transaction.js:45
        return (0, _possibleConstructorReturn3.default)(this, (FBClient.__proto__ || (0, _getPrototypeOf2.default)(FBClient)).call(this, props));
                                                                                                                              ^

TypeError: Class constructor Client cannot be invoked without 'new'
    at new FBClient (/Users/akshaysood/Blockchain/fabricSDK/dist/application/Transaction.js:45:127)
    at Object.<anonymous> (/Users/akshaysood/Blockchain/fabricSDK/dist/application/Transaction.js:195:14)
    at Module._compile (module.js:641:30)
    at Object.Module._extensions..js (module.js:652:10)
    at Module.load (module.js:560:32)
    at tryModuleLoad (module.js:503:12)
    at Function.Module._load (module.js:495:3)
    at Module.require (module.js:585:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/akshaysood/Blockchain/fabricSDK/dist/routes/users.js:11:20)

What I am trying to do is, I have created a class and then created an instance of that class. Then I am trying to export that variable.

The class structure is defined below:

class FBClient extends FabricClient{

    constructor(props){
        super(props);
    }

<<< FUNCTIONS >>>

}

How I am trying to export the variable ->

var client = new FBClient();
client.loadFromConfig(config);

export default client = client;

You can find the full code here --> Link. Code generated by Babel --> Link.

Eastsoutheast answered 15/8, 2018 at 13:51 Comment(7)
I'm not sure that you can export the instance of a class. I think you have to export the class, import it in another, then create the instance thereZinfandel
@Zinfandel - You can export any value, including an instance of a class.Mutate
@T.J.Crowder This code can not be run online as it requires Blockchain module.Eastsoutheast
@AkshaySood - The error is clearly not about blockchain stuff, it's about basic class definition and instantiation. Please read that MCVE link. You're not expected to post all your code. You're expected to work through a process producing a minimal replicating example. You haven't even shown us the class where the error is occurring.Mutate
Are you using Babel to transpile your code? (possibly related issue, but just a guess)Atmospheric
@Atmospheric Yes I am using BabelEastsoutheast
Notice that you should not use class syntax anyway if you want your module to export a singleton object. If you think you need instances, then you should export the class itself.Tagore
T
118

The problem is that the class extends native ES6 class and is transpiled to ES5 with Babel. Transpiled classes cannot extend native classes, at least without additional measures.

class TranspiledFoo extends NativeBar {
  constructor() {
    super();
  }
}

results in something like

function TranspiledFoo() {
  var _this = NativeBar.call(this) || this;
  return _this;
}
// prototypically inherit from NativeBar 

Since ES6 classes should be only called with new, NativeBar.call results in error.

ES6 classes are supported in any recent Node version, they shouldn't be transpiled. es2015 should be excluded from Babel configuration, it's preferable to use env preset set to node target.

The same problem applies to TypeScript. The compiler should be properly configured to not transpile classes in order for them to inherit from native or Babel classes.

Tetanus answered 15/8, 2018 at 14:38 Comment(12)
As the answer says. Change Babel configuration to not transpile to ES5. es2015 preset is responsible for this behaviour.Tetanus
If I do not transpile ES6 into ES5 using Babel. It throws error :unexpected token import:Eastsoutheast
The manual covers that, babeljs.io/docs/en/babel-preset-env . Use 'target node'.Tetanus
estus. Do you know how to use ES6 in Nodejs without Babel?Eastsoutheast
Just use it, all features except ES modules are available, node.green . ES modules are experimental and need .mjs extension, you may want to use require and module.exports for now. Babel is useful only for using features that are not there, like class fields and decorators.Tetanus
Ok So that means we can not use export & import without babel? Can we use classes & constructors and other features without babel?Eastsoutheast
Yes, we can use export and import, but this feature is experimental and isn't very practical in its current implementation, see nodejs.org/api/esm.html , I'd suggest to stick to CJS modules for real work. Yes, we can use them, see node.greenTetanus
For me i had to remove 'use babel';! Thanks!!Anthropometry
How stupid is it that typeof class A {} === 'function' yet A.call() throws an error?Diphosgene
@Diphosgene Technically it works like function A() { if (!new.target) throw new Error('cannot be invoked without new') }. A has its terms but it's definitely a function.Tetanus
Please do keep in mind that, while this would work okay for a node (and that's enough to answer the question), it won't help much if you're trying to target a browser.Cortico
@Cortico Indeed, at least if this means the support of legacy browsers (browser app shouldn't necessarily be ES5 in 2020). If there's a class that extends built-in class (Error, Promise, etc.), it should be extended in a special way to be compatible with ES5, this is covered in other questions on SO. If a class extends native ES6 class, it's the existence of untranspiled class in ES5 app that is a real issue.Tetanus
M
39

I was transpiling not Javascript but Typescript, and ran into the same problem.

I edited the Typescript compiler config file, tsconfig.json, to generate ES2017 Javascript code:

{
    "compilerOptions": {
        "target": "ES2017",

instead of whatever the default is, ES2015? — then all worked fine.

(Maybe this answer can be helpful for people who use Typescript and find this question when they search for the same error message, like I did.)

Miletus answered 5/4, 2020 at 2:4 Comment(2)
This worked for me as well. changed "target": "es5" to >> "target": "es2017"Flagellant
this answer worked for me as well. i changed "target": "es5" to "target": "ES2020"Carmina
M
17

For those who are using ts-node, it could be possible that your tsconfig.json is unable to be loaded by ts-node.

  1. Make sure you've set the below option for tsconfig.json:
    {
        "compilerOptions": {
            "target": "ES6",
            ...
        }
    }
  1. Try ts-node --script-mode or use --project to specify the path of your tsconfig.json.
Mid answered 28/5, 2020 at 9:43 Comment(0)
W
8

In package.json you can use targets configuration with @babel/preset-env. set the esmodules as 'true'.

Below is the example how I am using in my file:

  "babel": {
    "presets": [
      [
        "@babel/preset-env",
        {
          "targets": {
            "esmodules": true
          }
        }
      ],
      "@babel/preset-react",
      "@babel/preset-flow"
    ],
    "plugins": [
      "@babel/plugin-proposal-class-properties"
    ]
  },
Woodsman answered 2/4, 2020 at 11:11 Comment(0)
L
3

For Angular 9+ this can be probably a matter of using typescript compilation flags also:

  • downlevelIteration
  • importHelpers

More info hereL https://www.typescriptlang.org/tsconfig#downlevelIteration.

Try to use this flags in your tsconfig.josn:

{
    "compilerOptions": {
        ...
        "downlevelIteration": true,
        "importHelpers": true,
        ...
    }
}

Without "importHelpers": true it should also works.


This solution is mostly for Angular 9+ and ngcc compiler - this was an issue that occur for Angular 11. A custom configuration (custom ng-packgr config - Angular CLI library generating was introduced in Angular 6) for packages was maintained since there was Angular 4+ in the project. After miagration these packages to Angular 9+ libraries (projects folder) the error started occuring. I found that these flags (sctrictly downlevelIteration) solve exactly the problem.

Lagunas answered 14/7, 2021 at 19:28 Comment(1)
And also target to es6Edette
L
1

If you are not using babel and simple typescript. I got the error in material. Try to reduce the versions and bring them down to similar versions. My packages were having variety of versions.I solved the issue by lowering the package versions of packages like cdk, material.

Check the image of my final package.json

Longevity answered 3/7, 2020 at 20:45 Comment(0)
R
1

Check your "entities" array in appmodule.ts I also missed that. When I kept the entity name that is used in query, issue resolved. Hope this answer helps.

Retraction answered 30/1, 2023 at 17:47 Comment(0)
P
1

i used wrote before my ObjectId in nextjs and it worked.

Polymerize answered 5/7, 2023 at 18:1 Comment(2)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Juniejunieta
I wrote new before ObjectId in my Mongodb insertMany(), and it removes my errorTelevision
A
0

If you have already all these configurations on tsconfig and still it doesn't work maybe you have tsconfig.base file. try to chenge it too.

Anybody answered 15/2 at 13:8 Comment(0)
F
0

You can wrap instead of extending if you're not in TypeScript

In my situation, I didn't want to change the babel configuration (yet) and wanted to make the logic just work. Understanding a transpiled class cannot extend a native ES6 class I decided to simply wrap the base class, add functions to it and expose it (shoulnd't work in TypeScript).

My original code was something like:

import BaseClass from 'other-library';
class MyClass extends BaseClass {
  constructor(options) {
    super(options);

    this.on('event', this.action);
  }

  action(args) {
    // Custom logic for extending the BaseClass
  }
  addedAction(args) {
    // Custom logic for extending the BaseClass
  }
};

new MyClass({ args: ... }); // This throws "Class constructor BaseClass cannot be invoked without 'new'"

And I changed inheritance to wrapping like this:

import BaseClass from 'other-library';
class MyClass {
  constructor(options) {
    this.wrapped = new BaseClass(options);
    this.wrapped.addedAction = this.addedAction.bind(this);
    this.wrapped.on('event', this.action);
  }

  action(args) {
    // Custom logic for extending the BaseClass
  }
  addedAction(args) {
    this.wrapped.doSomething();
  }
};

// To get the base instance:
new MyClass({ args: ... }).wrapped;

Notice that after creating an instance of MyClass I simply access .wrapped to get the BaseClass instance

Forb answered 24/3 at 11:0 Comment(0)
A
-10

I hope you have already been able to solve your problem, here is my solution for this error:

class indexRoutes
{
    
    public  router: Router= Router();
}
const INDEX_ROUTES = new indexRoutes();
export default INDEX_ROUTES.router;
Arras answered 21/10, 2019 at 5:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.