Class constructor cannot be invoked without 'new'

Issue

Appreciate that this questions has been asked a few times, but almost all the cases that I’ve encountered have been the ones where someone tried to extend a non-native class. My case is different. I have a very simple base class called CObject which is as follows:

export class CObject extends BaseObject {
    constructor() {
        super();
    }
    static url(path: string): string { return ""; }
    static wssUrl(): string { return ""; }
    static callMethod(method, path: string, params: any, noConvertData?: boolean): Promise<any> { return null; }
    static post(path: string, params: any, noConvertData?: boolean): Promise<any> {
        return CObject.callMethod('post', path, params, noConvertData);
    }

    static put(path: string, params: any, noConvertData?: boolean): Promise<any> {
        return CObject.callMethod('put', path, params, noConvertData);
    }

    static patch(path: string, params: any, noConvertData?: boolean): Promise<any> {
        return CObject.callMethod('patch', path, params, noConvertData);
    }

    static get(path: string, params: any, noConvertData?: boolean): Promise<any> {
        return CObject.callMethod('get', path, params, noConvertData);
    }

    static delete(path: string, params: any, noConvertData?: boolean): Promise<any> {
        return CObject.callMethod('delete', path, params, noConvertData);
    }
}

The entire hierarchy of classes including BaseObject, are just simple Typescript classes. However, when I extend a class from CObject and then try instantiating it, I get this dreaded error (4 days now!). The funny thing is that I can instantiate CObject on it’s own without any issues. It’s just derived classes that are giving the issue, even empty ones like this:

export class TestClass extends CObject {
    constructor() {
        super();
    }
}

A point to note is that this code is shared between my Server (Node.js) and Client sides. The code works perfectly fine on the server side. No issues whatsoever.
I have tried looking at the babel generated code and it’s just simple ES6 classes. All other TS generated classes work as fine and everything below CObject fails when it gets to calling the CObject constructor.

My .babelrc is given below:

{
    "presets": [
        "es2015-node5",
        "react",
        "stage-0",
        "stage-1",
        "bluebird"
    ],
    "plugins": [
        "transform-decorators-legacy",
        "react-hot-loader/babel",
        "transform-async-to-bluebird",
        "transform-promise-to-bluebird",
        "transform-runtime",
        [
            "module-alias", 
            [
                { "src": "./build/Server", "expose": "Server" },
                { "src": "./build/Shared", "expose": "Shared" },
                { "src": "./build/Client", "expose": "Client" }
            ]
        ]
    ],
    "compact": "false"
}`

For client side compilation, my awesome-typescript-loader config in tsconfig.json is as follows:

EDIT: I was looking at the wrong ATL config. The full config is as follows:

"awesomeTypescriptLoaderOptions": {
    "babelrc": true,
    "useBabel": true,
    "useWebpackText": true,
    "useTranspileModule": true,
    "doTypeCheck": true,
    "forkChecker": true,
    "presets": ["env", { "targets": "last 2 versions, ie 11", "modules": false }, { "exclude": ["transform-es2015-classes"] } ],
    "babelOptions": {
        "sourceMaps": true
    },
    "useCache": true
}

Client side webpack config is as follows:

var path = require('path');
var webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

let outputDir = path.join(__dirname, "..", "dist", "Client");
console.log(`Output: ${outputDir}`);

module.exports = {
    entry: "./src/Client/Browser/Src/Main.tsx",
    output: {
        filename: "client.js",
        path: outputDir
    },
    target: 'web',

    // Enable sourcemaps for debugging webpack's output.
    devtool: "source-map",

    resolve: {
        // Add '.ts' and '.tsx' as resolvable extensions.
        extensions: [".ts", ".tsx", ".js", ".json"],
        plugins: [new TsconfigPathsPlugin({ configFile: "./tsconfig.json" })],
        modules: [
            "./node_modules",
            "./src/Shared",
            "./src/Client"
        ]
    },

    module: {
        rules: [
            // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
            { test: /\.tsx?$/, loader: "awesome-typescript-loader" },

            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            { enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
        ]
    }
};

Any help will be appreciated. Thank you.

Edit: The exact error is:

ConfigSection.ts?26cc:18 Uncaught TypeError: Class constructor CObject cannot be invoked without 'new'
    at new ConfigSection (ConfigSection.ts?26cc:18)
    at Object../src/Shared/Model/Config/ShAlpha.ts (ShAlpha.ts:338)
    at __webpack_require__ (bootstrap:19)

Solution

Ok, thanks to Oscar Paz, I have been able to fix the issue. Turns out that the culprit was my ATL config:

"awesomeTypescriptLoaderOptions": {
    "babelrc": true,
    "useBabel": true,
    "useWebpackText": true,
    "useTranspileModule": true,
    "doTypeCheck": true,
    "forkChecker": true,
    "presets": ["env", { "targets": "last 2 versions, ie 11", "modules": false }, { "exclude": ["transform-es2015-classes"] } ],
    "babelOptions": {
        "sourceMaps": true
    },
    "useCache": true
}

More specifically, this line:

    "presets": ["env", { "targets": "last 2 versions, ie 11", "modules": false }, { "exclude": ["transform-es2015-classes"] } ],

even though I’d set:

    "babelrc": true,

Expecting the .babelrc to get used, which is what was getting used for the Node.js code. This was causing multiple definitions (both ES6 and ES5) of the classes derived from CObject to be generated. So CObject was getting generated correctly:

let CObject = exports.CObject = class CObject extends _BaseObject.BaseObject {} ...

The first definition of ConfigSection was also getting generated correctly:

let ConfigSection = ConfigSection_1 = class ConfigSection extends Shared_Core_CObject__WEBPACK_IMPORTED_MODULE_1__["CObject"] {} ...

But then further down:

var ConfigSection = ConfigSection_1 = function (_CObject) {
    (0, _inherits3.default)(ConfigSection, _CObject); ...

This is what was causing the error. I don’t know why ATL isn’t ignoring those options and why those options cause this sort of code-gen. Perhaps, someone with a better understanding can shed some light.

Answered By – GlGuru

Answer Checked By – Candace Johnson (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.