类构造函数不能在没有使用“new”关键字的情况下调用 - 使用CommonJS的TypeScript

31
我正在使用 colyseus(node 游戏服务器框架)制作服务器端聊天。我在使用 typescript 和模块 commonjs,因为 colyseus 是基于 commonjs 构建的。
我有一个名为 ChatRoom 的类,它扩展了 Colyseus.Room。 在运行时,我收到以下错误:
Class constructor Room cannot be invoked without 'new'.

而在JavaScript中的问题:

function ChatRoom() {
   return _super !== null && _super.apply(this, arguments) || this;
}

来自 TypeScript 类:

import {Room} from "colyseus";

export class ChatRoom extends Room {

    onInit(options) {
        console.log("BasicRoom created!", options);
    }

    onJoin(client) {
        this.broadcast(`${ client.sessionId } joined.`);
    }

    onLeave(client) {
        this.broadcast(`${ client.sessionId } left.`);
    }

    onMessage(client, data) {
        console.log("BasicRoom received message from", client.sessionId, ":", data);
        this.broadcast(`(${ client.sessionId }) ${ data.message }`);
    }

    onDispose() {
        console.log("Dispose BasicRoom");
    }
  }

当编译完成后,删除出错行就可以轻松跳过错误。但是基类没有被创建,这不是一个完整的解决方案。

我通过谷歌查询了这个问题,似乎与Babel转换器有关,尽管我没有使用Babel。我只使用tsc / tsconfig.json。

3个回答

74

TypeScript将类转译为其ES5对应项,但这样做需要将整个类层次结构转译为ES5。

如果父类未转译(原生类或导入的ES6类,包括使用Babel转译的类),这将无法正常工作,因为TypeScript依赖于var instance = Parent.call(this, ...) || this技巧来调用父级构造函数,而ES6类只能通过new进行调用。

在Node.js中,可以通过将TypeScript的target选项设置为es6或更高版本来解决此问题。现代Node.js版本支持ES6类,无需对其进行转译。

同样的问题也适用于Babel


8
谢谢。这个有效: tsconfig.compilerOptions: {target : "es6",..}翻译:感谢。这是有效的: tsconfig.compilerOptions: {target : "es6",..} (说明:原文为英文代码,翻译为中文) - Александър К.
4
或者,如果您需要es5支持,请确保使用target: es5编译所有层次结构。这是我的建议! - cancerbero
1
这是一个关于你的 Node 版本应该使用哪个 target 的表格 https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping - Tamlyn

27

如果您正在使用ts-node,可能会出现tsconfig.json无法被ts-node加载的情况。

  1. 请确保为tsconfig.json设置了以下选项:
{
    "compilerOptions": {
        "target": "ES6",
        ...
    }
}
  1. 尝试使用 ts-node --script-mode 或者使用 --project 来指定你的 tsconfig.json 的路径。

2
这解决了我的问题!我不得不从ES5切换到ES6,然后它就起作用了。 - Megan
非常感谢您的答复。我尝试过了,但我无法按照您在“步骤2”中提到的内容进行操作。 我正在使用Nuxt.js。https://dev59.com/tGsMtIcB2Jgan1znzbNr - BATMAN_2008
@BATMAN_2008 你在使用ts-node吗?使用ts-node时,我们会像这样调用ts-node ./index.ts来启动我们的应用程序。根据我的答案,我们可以使用ts-node --script-mode ./index.ts - Devo
我使用 ts-node --project tsconfig.json 成功了! - Daniel Hair
很遗憾,我按照你的建议创建了一个tsconfig.json文件,但我仍然收到了那个错误。 - Alaska

4
我在使用JavaScript、Webpack和Babel时遇到了同样的问题(但没有TypeScript)。
我找到了一个基于ES6/Babel Class constructor cannot be invoked without 'new'的解决方案。
我需要在我的Babel加载器中明确地包含colyseus。以下是我的webpack配置文件中的片段:
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        include: /colyseus/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接