digs
digs

Reputation: 41

TypeError: Class constructor Client cannot be invoked without 'new'

I'm working on a discord bot framework that uses ts-node (in script mode), typescript, and discord.js. When testing the core client class I got this error:


C:\Users\thedi\Documents\coding\JS-TS\discord-bot\src\struct\Client.ts:13
        super()
        ^
TypeError: Class constructor Client cannot be invoked without 'new'
    at new DigsClient (C:\Users\thedi\Documents\coding\JS-TS\discord-bot\src\struct\Client.ts:13:9)
    at Object.<anonymous> (C:\Users\thedi\Documents\coding\JS-TS\discord-bot\test\index.ts:6:16)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Module.m._compile (C:\Users\thedi\AppData\Roaming\npm\node_modules\ts-node\src\index.ts:1056:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Object.require.extensions.<computed> [as .ts] (C:\Users\thedi\AppData\Roaming\npm\node_modules\ts-node\src\index.ts:1059:12)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at main (C:\Users\thedi\AppData\Roaming\npm\node_modules\ts-node\src\bin.ts:198:14)

There are many answers to this same question around StackOverflow, and most suggested setting the 'target' value in your tsconfig to 'es6' or higher. My problem is that the solution doesn't work for me.

Here's my code:

// src/struct/Client.ts

import { Client, ClientOptions, Snowflake } from 'discord.js';
import * as discord from 'discord.js';

interface DigsClientOptions {
    ownerID?: Snowflake | Array<Snowflake>;
}

class DigsClient extends Client {
    public constructor(
        options?: DigsClientOptions,
        discordOptions?: ClientOptions
    ) {
        super();

        this.ownerID = options.ownerID;

        return this;
    }

    ownerID: Snowflake | Array<Snowflake>;
}

export { DigsClient, DigsClientOptions };

// test/index.ts

import { DigsClient } from '../src/index';
import { config } from 'dotenv';
config();
const token = process.env.TOKEN;

const client = new DigsClient({ ownerID: '585813838490894346' });

client.login(token);

//.tsconfig.json

{
    "compilerOptions": {
        "target": "es6",
        "module": "es6"
    },
    "exclude": ["node_modules"]
}


This error occurs when using ts-node and ts-node-script, and I know it detects the tsconfig as I don't get errors for using es6 modules.

Hope anyone can help!

Upvotes: 3

Views: 13838

Answers (1)

nouvist
nouvist

Reputation: 1182

Since NodeJS follows the CommonJS module system, I think the cause is you should set module to CommonJS. And you can keep the target to ES6 as far it is not break. Because AFAIK, Node and modern Browsers support ES6 syntax.

But, then what the difference between target and module. target is the whole syntax you targeting to, while module is only just for how you import other module. And NodeJS is only supports CommonJS until version 14.x. So, it is recommended to use CommonJS on NodeJS Typescript Project.


Like what I said, it just how you could import other module. CommonJS is a module system which is a system that allows you to import other modules, like <script> tag on html. Here's CommonJS example.

const foobar = require('./foobar.js');
foobar();

NodeJS using this module system because Javascript didn't have one yet.

But then, EcmaScript (Javascript standard) introduces ESModule which is a standardized alternative to CommonJS. ESModule is part of EcmaScript standard syntax. And its syntax look like this.

import foobar from './foobar.js';
foobar();

So, you are using ESModule, but NodeJS is only understand CommonJS. That's why we need to compile the ES6 to CommonJS, so NodeJS can understand.


But now, NodeJS supports ESModule on 13.x or 14.x (I'm not fully sure). But NodeJS will still use CommonJS as default. So, you need to tell NodeJS that your package is using ESModule if you want to use it.

There's several option to do so. First, using .mjs extension, and second is change it as default on package.json.

{
  "name": "my-epic-package",
  "version": "1.0.0",
  "type": "module", // here
  ...
}

So, with the type module enabled, you can keep the tsconfig.json to use module.

Upvotes: 2

Related Questions