类型错误:无法在没有“new”的情况下调用类构造函数model。

6
我在一个应用程序中使用Sequelize、Node和JavaScript。当您执行sequelize-init时,它会创建configmigrationsmodelsseeders文件夹。在models文件夹中,有一个index.js文件(由cli生成),负责从当前文件夹读取所有模型及其关联:
'use strict';

const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const sequelize = require('../database/connection');
const db = {};

fs
  .readdirSync(__dirname)
  .filter(file => {
    return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
  })
  .forEach(file => {
    const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
    db[model.name] = model;
  });

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;

当我运行我的应用程序时,会出现一个错误: TypeError: Class constructor model cannot be invoked without 'new' ,该错误出现在第17行,即下面这个语句:var model = require(path.join(__dirname,file))(sequelize,Sequelize.DataTypes); 通过阅读一些与此问题相关的帖子,我发现我需要安装@babel/preset-env包以及@babel/cli,@babel/core,@babel/node。 我还在根目录中创建了一个.babelrc文件,其中包含以下代码:
{
    "presets": [
      [
        "@babel/preset-env",
        {
          "targets": {
            "esmodules": true
          }
        }
      ]
    ]
}

我更新了package.jsonscripts标签下的start选项,将其更改为:"nodemon --exec babel-node app.js"(我不使用webpack)

但是当我运行应用程序时仍然出现错误。我错过了什么或者没有正确设置?


6
你不需要为一个Node.js程序安装Babel!你只需要使用new关键字而不是像调用函数一样调用一个类(就像错误提示你的那样):const ThingThatIsAClass = require(path.join(__dirname, file)); const model = new ThingThatIsAClass(sequelize, Sequelize.DataTypes); 不要试图在一行代码中塞入过多内容。这会让代码难以阅读,并容易错过像这个一样微不足道的错误。 - Jared Smith
非常抱歉我的无知,我不知道这一点。我理解错误在于调用构造函数的方式,但从未想过要拆分语句。谢谢! - CodiClone
2
你不必拆分语句,也可以写成 new (require(…))(…),但这样更难理解。 - Bergi
2
@CodiClone 不需要道歉,编程很难,缺乏经验并不意味着道德上的失败 :) - Jared Smith
2个回答

22

注意:如果您想了解更多,请在末尾查看“为什么”部分!

问题

问题是ES6类没有被完全转换成ES5,并且Sequelize依赖于某些特性

或者

使用Sequelize.import代替require!不要这样做!(Babel或任何转换器适用于require(或es import),而sequelize.import的工作方式会导致问题!)

答案

我想您正在使用

export class Course extends Model {} // <== ES6 classes

Course.init({

是你的babel配置导致了这个问题!

你可以在这个评论的GitHub主题中进行检查。

这对那个人起作用了。

{
  "presets": [
    ["env", {
      "targets": {
        "node": "current"
      }
    }]
  ]
}

或者

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": true
        }
      }
    ]
  ]
}

评论

让Babel使用ES6类!

请注意,另一方面,如果您只是坚持使用sequelize.define()方式

export const User = sequelize.define('User', {
  // Model attributes are defined here
  firstName: {
    type: DataTypes.STRING,
    allowNull: false
  },

在ES5中它将完美工作!

不要使用Sequelize.import来导入模型

如果您正在这样做,请不要这样做!使用require或es import!转译器无法直接处理Sequelize.import!这似乎会引起问题。

评论说明了这一点。

对我而言,这是由于ES6与Typescript之间的问题。

Typescript

默认目标是ES5

将其更改为ES6+!一切就开始工作了!

例如:

"target": "ES2021", 

使用sequelize.define的ES5可以工作

请注意,使用sequelize.define的ES5可以很好地工作!

enter image description here

使用Class extends的ES5无法工作

enter image description here

示例

enter image description here

ES6+始终可用

enter image description here

enter image description here

为什么?Babel通常不能正确转译!!!???

您可以在此github注释中查看。

事实证明,通过babel转译的ES6类不能扩展真正的ES6类(例如Sequelize.Model ES6类)。
因此,如果将MyEntity类转译为ES5,则无法使用class MyEntity extends Sequelize.Model {...}。

这里是stackoverflow答案更好的解释:https://dev59.com/GFoV5IYBdhLWcg3wL8Ww#36657312

由于ES6类的工作方式,您不能使用转译的类扩展原生类。 如果您的平台支持原生类

您可以在以下链接中了解有关如何可能进行ES6类到ES5的完全特性和兼容性支持的转译的深度元素。

https://github.com/microsoft/TypeScript/issues/17088

https://github.com/microsoft/TypeScript/issues/15397

这里有一篇文章(比较将ES6类转换为ES5的不同方法)更详细地介绍了这个主题。


感谢您的详细解释! - CodiClone

0
如果在tsconfig.json文件的"target"中有"es5",请将其更改为"es6"。(这对我有效,并且我需要编译器中的es6。)
"compilerOptions": {
    "target": "es6"
}

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