TypeError:没有'new'就不能调用类构造函数模型

我在一个应用中同时使用 Sequelize 以及 Node 和 JavaScript.如您所知,当您执行 sequelize-init 时,它会创建 config、migrations、models 和 seeders 文件夹.在 models 文件夹内,有一个 index.js 文件(由 cli 生成),负责从当前文件夹中读取所有模型及其关联:

index.js

'使用严格';常量 fs = 要求('fs');常量路径 = 要求('路径');const Sequelize = require('sequelize');const basename = path.basename(__filename);const sequelize = require('../database/connection');常量 db = {};fs.readdirSync(__dirname).filter(文件=> {return (file.indexOf('.') !== 0) &&(文件!==基本名称)&&(file.slice(-3) === '.js');}).forEach(文件 => {常量模型 = 要求(path.join(__dirname,文件))(续集,Sequelize.DataTypes);db[model.name] = 模型;});Object.keys(db).forEach(modelName => {if (db[modelName].associate) {db[modelName].associate(db);}});db.sequelize = 续集;db.Sequelize = 续集;模块.出口=分贝;

当我运行我的应用程序时,出现错误:TypeError: Class constructor model cannot be invoked without 'new' 在第 17 行,它是语句:var model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); 阅读一些

带有类扩展的 ES5 不起作用

插图

ES6+ 始终有效

为什么!Babel 通常不会正确转换!!???

你可以在这个github上看到评论

<块引用>

事实证明,通过 babel 转译的 ES6 类不能扩展真正的 ES6 类(例如 The Sequelize.Model ES6 类).
所以如果 MyEntity 被转译成 ES5,class MyEntity extends Sequelize.Model { ... } 将不起作用.

这里的stackoverflow答案解释得更好:https://stackoverflow.com/a/36657312/7668448

<块引用>

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

您可以看到更多关于为什么以及如何将 ES6 类转换为 ES5 以支持完整功能和兼容性的原因和可能性!在下面的链接中:

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

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

这里有一篇文章(compare-different-ways-of-transpiling-es6-class-to-es5),详细介绍了该主题

I'm using Sequelize together with Node and JavaScript in one app. As you know when you execute sequelize-init it creates config, migrations, models and seeders folder. Inside of the models folder, there is an index.js file (generated by the cli), which is responsible for reading all of the models and their associations from the current folder:

index.js

'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;

When I run my app, an error appears: TypeError: Class constructor model cannot be invoked without 'new' at line 17 which is the statement: var model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); Reading some of the posts related to this problem I found out that I need to install the @babel/preset-env package along with @babel/cli, @babel/core, @babel/node. I also created a .babelrc file in the root directory, containing the following code:

.babelrc

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

and updated my start option of the scripts tag inside package.json to: "nodemon --exec babel-node app.js" (I don't use webpack)

But when I run the app the error still appears. What do I miss or haven't set correctly?

解决方案

Note: Check the Why section in the end! If you want to know.

Problem

The problem is ES6 classes => are not transpilled with there full features to ES5! Sequelize is relying on some features

Or

Using Sequelize.import in place of require! Don't! (Babel or any transpiler works with require (or es import) and how sequelize.import work is causing problem!)!

Answer

I guess you are using

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

Course.init({

Your babel configuration is what's causing that!

You can check that on this github thread comment

This worked for the guy

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

Or

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

comment

Making babel use ES6 classes!

Note that if in the other hand you just stick with sequelize.define() way

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

It will work just right in ES5!

Don't use Sequelize.import to import Models

If you are doing then don't! Use require or es import! The transpiler doesn't handle Sequelize.import directly! And it seems to cause problem

Comment showing that

For me it was because of ES6 with Typescript

Typescript

Default target was ES5!

Change that to ES6+! And all start working!

For example

"target": "ES2021", 

ES5 with sequelize.define works

Know that ES5 with sequelize.define works just fine!

ES5 with Class extends doesn't work

Illustration

ES6+ works always

Why! Babel doesn't normally transpile right!! ???

You can see that in this github comment

It turns out that an ES6-class transpiled by babel can't extend a real ES6 class (The Sequelize.Model ES6-class for example).
So class MyEntity extends Sequelize.Model { ... } won't work if MyEntity is transpiled into ES5.

And here the stackoverflow answer explaining better: https://stackoverflow.com/a/36657312/7668448

Due to the way ES6 classes work, you cannot extend a native class with a transpiled class. If your platform supports native classes

You can see more depth elements about the why and how possibly such a transpilation of ES6 Class to ES5 can be done to support full features and compatiblity! in the links bellow:

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

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

And here an article (comparing-different-ways-of-transpiling-es6-class-to-es5) that go in more details about the subject

相关文章