【问题标题】:TypeORM Entity in NESTJS - Cannot use import statement outside a moduleNESTJS 中的 TypeORM 实体 - 无法在模块外使用导入语句
【发布时间】:2020-04-13 13:26:42
【问题描述】:

使用“nest new”命令启动新项目。在我向其中添加实体文件之前工作正常。

出现以下错误:

从 'typeorm' 导入 { Entity, Column, PrimaryGeneratedColumn };

^^^^^^

SyntaxError: 不能在模块外使用 import 语句

我错过了什么?

向模块添加实体:

import { Module } from '@nestjs/common';
import { BooksController } from './books.controller';
import { BooksService } from './books.service';
import { BookEntity } from './book.entity';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [TypeOrmModule.forFeature([BookEntity])],
  controllers: [BooksController],
  providers: [BooksService],
})
export class BooksModule {}

app.module.ts:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { BooksModule } from './books/books.module';

@Module({
  imports: [TypeOrmModule.forRoot()],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

【问题讨论】:

  • 从'@nestjs/common'导入{模块};
  • @Preston 想详细说明您的意思?是否必须为常用共享文件创建模块?
  • 您的错误是来自 linter 还是来自编译?你在哪里有这个新文件?它在您的src 目录中吗?如果您使用的是 TypeORM,您能否在 AppModuleimports 数组中显示您的 TypeOrmModule 导入?我们看不到的配置可能有问题
  • 更新了实体导入信息的帖子

标签: nestjs typeorm


【解决方案1】:

我的假设是您有一个 TypeormModule 配置和一个 entities 属性,如下所示:

entities: ['src/**/*.entity.{ts,js}']

或喜欢

entities: ['../**/*.entity.{ts,js}']

您遇到的错误是因为您试图在 js 上下文中导入 ts 文件。只要您不使用 webpack,您就可以使用它来获取正确的文件

entities: [join(__dirname, '**', '*.entity.{ts,js}')]

其中join 是从path 模块导入的。现在__dirname 将解析为srcdist,然后分别找到预期的tsjs 文件。如果还有问题,请告诉我。

编辑 2020 年 1 月 10 日

以上假设配置完成是一个javascript兼容文件(.jsTypeormModule.forRoot()传递的参数)。如果您改用ormconfig.json,则应使用

entities: ["dist/**/*.entity.js"]

这样你使用的是编译好的js文件,没有机会在你的代码中使用ts文件。

【讨论】:

  • 但这完全是一团糟。一个不接受用于迁移的打字稿的打字稿 ORM...
  • deno 是唯一的原生 typescript 代码运行器。 TypeORM,虽然它使用 Typescript,但仍然适用于 Node 和 JavaScript 运行时。也许可以进行改进以接受ts 文件并将它们编译为引擎盖下的JavaScript,然后删除它们以便最终用户看不到它们,但这需要作为TypeORM git存储库的问题提出
  • 实际上整行必须是 "entities": ["dist/**/*.entity.js"],因为 json 语法。
  • 我完全同意,为了让所有这些乱七八糟的东西工作而不得不进入转译的 JS 是一个笑话。
  • Github 上的 Issue #4283 详细解释了为什么应该使用 JavaScript 从 Dist 文件夹中读取实体。这是我在根文件夹ormconfig.js改的魔法线,你也可以试试看。 entities: ['dist/**/*.entity.js'] 是解决方案。
【解决方案2】:

在 TypeORM 文档中,我找到了 Typescript 的特定部分。

这部分说:

全局安装 ts-node:

npm install -g ts-node

在 package.json 的 scripts 部分下添加 typeorm 命令

"scripts" {
    ...
    "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js"    
}

然后你可以像这样运行命令:

npm run typeorm migration:run

如果您需要将带有破折号的参数传递给 npm 脚本,您将需要 在 -- 之后添加它们。例如,如果您需要生成, 命令是这样的:

npm run typeorm migration:generate -- -n migrationNameHere

这适用于我的文件配置:

{
    "type": "postgres",
    "host": "yourhost",
    "port": 5423,
    "username": "username",
    "password": "password",
    "database": "your_db",
    "synchronize": true,
    "entities": [
        "src/modules/**/*.entity.{ts,js}"
    ],
    "migrations": [
        "src/migrations/**/*.{ts,js}"
    ],
    "cli": {
        "entitiesDir": "src/modules",
        "migrationsDir": "src/migrations"
    }
}

然后就可以运行生成命令了。

【讨论】:

    【解决方案3】:

    正如 Jay McDoniel 在他的回答中解释的那样,问题似乎是 ormconfig.json 文件中实体文件的模式匹配:可能是从 javascript 文件(可能是以前转译的打字稿文件)导入了打字稿文件(模块)。

    删除ormconfig.json 中现有的ts glob 模式就足够了,这样TypeORM 将只加载javascript 文件。实体文件的路径应该是相对于节点执行的工作目录的。

       "entities"   : [
          "dist/entity/**/*.js"
       ],
       "migrations" : [
          "dist/migration/**/*.js"
       ],
       "subscribers": [
          "dist/subscriber/**/*.js"
       ],
    

    【讨论】:

    • src 可能应该更改为 dist,因为这是可运行代码在转译为 javascript 后所在的位置。
    • 我花了一点时间:在运行时,代码将从“dist”(分发)文件夹中运行。而包含数据库模型的 *.entity.ts 文件,会被 TypeOrm 翻译成 .js 文件。因此 - 实体条目应指向“dist”文件夹下的 *.entity.js。谢谢你们。拯救我的一天。
    【解决方案4】:

    我在 tsconfig.json 文件中更改了下一个:

    "module": "es6"
    

    收件人:

    "module": "commonjs",
    

    对我有帮助

    【讨论】:

    • 非常感谢。公认的答案很好,但这是我缺少的那一件。
    【解决方案5】:

    官方文档中提到的在ormconfig.json 中定义实体属性为我解决了这个问题。

    // This is your ormconfig.json file
    
    ...
    "entities": ["dist/**/*.entity{.ts,.js}"]
    ...
    

    【讨论】:

      【解决方案6】:

      这就是我设法解决它的方法。使用单个配置文件,我可以在应用程序 boostrap 或使用 TypeOrm 的 CLI 上运行迁移。

      src/config/ormconfig.ts

      import parseBoolean from '@eturino/ts-parse-boolean';
      import { TypeOrmModuleOptions } from '@nestjs/typeorm';
      import * as dotenv from 'dotenv';
      import { join } from 'path';
      
      dotenv.config();
      
      export = [
        {
          //name: 'default',
          type: 'mssql',
          host: process.env.DEFAULT_DB_HOST,
          username: process.env.DEFAULT_DB_USERNAME,
          password: process.env.DEFAULT_DB_PASSWORD,
          database: process.env.DEFAULT_DB_NAME,
          options: {
            instanceName: process.env.DEFAULT_DB_INSTANCE,
            enableArithAbort: false,
          },
          logging: parseBoolean(process.env.DEFAULT_DB_LOGGING),
          dropSchema: false,
          synchronize: false,
          migrationsRun: parseBoolean(process.env.DEFAULT_DB_RUN_MIGRATIONS),
          migrations: [join(__dirname, '..', 'model/migration/*.{ts,js}')],
          cli: {
            migrationsDir: 'src/model/migration',
          },
          entities: [
            join(__dirname, '..', 'model/entity/default/**/*.entity.{ts,js}'),
          ],
        } as TypeOrmModuleOptions,
        {
          name: 'other',
          type: 'mssql',
          host: process.env.OTHER_DB_HOST,
          username: process.env.OTHER_DB_USERNAME,
          password: process.env.OTHER_DB_PASSWORD,
          database: process.env.OTHER_DB_NAME,
          options: {
            instanceName: process.env.OTHER_DB_INSTANCE,
            enableArithAbort: false,
          },
          logging: parseBoolean(process.env.OTHER_DB_LOGGING),
          dropSchema: false,
          synchronize: false,
          migrationsRun: false,
          entities: [],
        } as TypeOrmModuleOptions,
      ];
      

      src/app.module.ts

      import configuration from '@config/configuration';
      import validationSchema from '@config/validation';
      import { Module } from '@nestjs/common';
      import { ConfigModule } from '@nestjs/config';
      import { TypeOrmModule } from '@nestjs/typeorm';
      import { LoggerService } from '@shared/logger/logger.service';
      import { UsersModule } from '@user/user.module';
      import { AppController } from './app.controller';
      import ormconfig = require('./config/ormconfig'); //path mapping doesn't work here
      
      @Module({
        imports: [
          ConfigModule.forRoot({
            cache: true,
            isGlobal: true,
            validationSchema: validationSchema,
            load: [configuration],
          }),
          TypeOrmModule.forRoot(ormconfig[0]), //default
          TypeOrmModule.forRoot(ormconfig[1]), //other db
          LoggerService,
          UsersModule,
        ],
        controllers: [AppController],
      })
      export class AppModule {}
      

      package.json

        "scripts": {
          ...
          "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ./src/config/ormconfig.ts",
          "typeorm:migration:generate": "npm run typeorm -- migration:generate -n",
          "typeorm:migration:run": "npm run typeorm -- migration:run"
        },
      
      

      项目结构

      src/
      ├── app.controller.ts
      ├── app.module.ts
      ├── config
      │   ├── configuration.ts
      │   ├── ormconfig.ts
      │   └── validation.ts
      ├── main.ts
      ├── model
      │   ├── entity
      │   ├── migration
      │   └── repository
      ├── route
      │   └── user
      └── shared
          └── logger
      

      【讨论】:

      • 我必须更新 migrations 以匹配您的语法
      【解决方案7】:

      当我遇到这个问题时,我正在使用带有 Typescript 和 TypeORM 的 Node.js。在 ormconfig.json 文件中配置对我有用。

      entities: ['dist/**/*.entity.js']
      

      我的 ormconfig.json 文件的完整代码:

      {
        "type": "mysql",
        "host": "localhost",
        "port": 3306,
        "username": "xxxxxxxx",
        "password": "xxxxxxxx",
        "database": "typescript_orm",
        "synchronize": true,
        "logging": false,
        "migrationTableName": "migrations",
        "entities": [
          "dist/**/*.entity.js"
        ],
        "migrations": [
          "src/migration/**/*.{ts, js}"
        ],
        "suscribers": [
          "src/suscriber/**/*.{ts, js}"
        ],
        "cli": {
          "entitiesDir": "src/model",
          "migrationDir": "src/migration",
          "suscribersDir": "src/suscriber"
        }
      }
      

      【讨论】:

        【解决方案8】:

        实际上,typeorm 被设计为默认使用 javascript。

        要使用 typescript 运行迁移,您必须告诉 typeorm 这样做。

        只需在你的 package.json 中,在脚本部分下面这一行:

        "typeorm": "ts-node-dev ./node_modules/typeorm/cli.js"
        

        然后,再次尝试迁移:

        yarn typeorm migration:run
        

        【讨论】:

          【解决方案9】:

          与其他人的 cmets 一致 - 实际上,必须依赖生成的代码才能使其工作似乎很愚蠢。我不相信这个解决方案,因为它是其他人的存储库,但它实际上只允许完整的 Typescript 迁移。它依赖于.env 文件的Typeorm 值而不是ormconfig.json,尽管我确信它可以被翻译。我发现它有助于我消除对 .js 文件的依赖。

          这里是回购: https://github.com/mthomps4/next-now-test/tree/next-typeorm-example

          解释它的工作原理:

          除了您通常的 .env 或 ormconfig.json 文件,其中包含正确的 localhost db 连接,您还需要在 ormconfig.json 或 .env 文件中正确指定以下内容

          TYPEORM_ENTITIES="entities/*.ts"
          TYPEORM_MIGRATIONS="migrations/*.ts"
          TYPEORM_ENTITIES_DIR="entities"
          TYPEORM_MIGRATIONS_DIR="migrations"
          

          请注意,实体和迁移 glob 只有 *.ts。另一个非常重要的部分是如何设置您的 npm 脚本以使用 ts-node 运行。

          您需要一个扩展的 tsconfig,其中包含以下内容:

          {
            "extends": "./tsconfig.json",
            "compilerOptions": {
              "module": "commonjs"
            }
          }
          

          这就是允许 ts-node 在生成迁移时正确“拾取” .ts 文件的原因。

          这个 npm 脚本(DOTENV 部分仅在使用 .env 文件而不是 ormconfig.json 时)指定使用 tsconfig.json

           "local": "DOTENV_CONFIG_PATH=./.env ts-node -P ./tsconfig.yarn.json -r dotenv/config"
          

          这被用作“前导”脚本:

          "typeorm:local": "yarn local ./node_modules/typeorm/cli.js"
          

          我不是 100% 确定所有这些都是必要的(您可以内联完成),但它对我有用。基本上这是说“在具有特定 .env 文件和特定 tsconfig 的 ts-node 上下文中调用 typrorm cli”。在某些情况下,您也许可以跳过这些配置。

          最后,这个脚本现在可以工作了:

          "g:migration": "yarn typeorm:local migration:generate -n"
          

          所以通过运行:

          npm run g:migration -- User
          

          您将获得根据您当前更改的实体自动生成的迁移文件!

          在 3 个嵌套的 npm 脚本之后,我们有一个非常具体的方法来运行“生成”迁移命令,并使用所有正确的配置来使用 only TS 文件。是的 - 难怪有些人仍然反对打字稿,但幸运的是,这确实有效,如果你想尝试一下它是如何“正常工作”的,上面的示例 repo 已经预先配置好了。

          【讨论】:

          • 谢谢你;有用!
          【解决方案10】:

          还要检查实体中的导入。不要import { SomeClassFromTypeorm } from 'typeorm/browser';,因为这会导致同样的错误。

          在我的 IDE 自动导入错误的包后发生在我身上。从导入中删除 '/browser'

          【讨论】:

          • 它可以帮助其他任何人,在我的 Nestjs 和 typeorm 项目中也发生了同样的事情。 import { Unique } from 'typeorm/browser';只需要改成import { Unique } from 'typeorm';
          【解决方案11】:

          您需要为应用的每个部分创建一个 something.module.ts。它像 Angular 一样工作。这是使用 GraphQL 解析器和服务设置的。 REST 与控制器有点不同。每个模块可能都有一个实体,如果是 GraphQL,则为 projects.schema.graphql。

          projects.module.ts

          import { Module } from '@nestjs/common';
          import { TypeOrmModule } from '@nestjs/typeorm';
          import { ProjectsService } from './projects.service';
          import { Projects } from './projects.entity';
          
          import { ProjectsResolvers } from './projects.resolvers';
          
          @Module({
            imports: [
              TypeOrmModule.forFeature([Projects])],
            providers: [
              ProjectsService,
              ProjectsResolvers
            ],
          
          })
          
          export class ProjectsModule {}
          

          【讨论】:

          • 优秀。那么这是否意味着您可以在多个模块之间共享一个基本实体,或者该基本实体必须是某种公共模块的一部分?
          • 我想我已经将实体导入到模块中。请查看更新后的帖子
          • 抱歉,Anton,我现在正在度假,要到一月份才能帮到你。我将不得不查看我的旧 REST 模块,但我没有随身携带它们。
          • Anton,如果您已经解决了这个问题,请将您的解决方案发布到 SO。
          【解决方案12】:

          这对我有用 - 无需更改您的 ormconfig.js。从 node_modules 所在的根目录运行:

          ts-node ./node_modules/typeorm/cli.js  migration:generate -n <MirgrationName> -c <ConnectionType>
          

          例子:

          ts-node ./node_modules/typeorm/cli.js  migration:create -n AuthorHasMultipleBooks -c development 
          

          【讨论】:

            【解决方案13】:

            我认为比公认的更好的解决方案是在您选择的 shell 中创建一个别名,在 node_modules 内使用 ts-node

            注意:我在 bash 中使用 OhMyZsh 执行此操作,因此您的配置可能完全不同。

            1:打开shell配置

            打开shell配置1

            nano ~/.zshrc
            

            2:找到定义了其他别名的地方,添加一个新的别名

            alias typeorm="ts-node ./node_modules/typeorm/cli.js"
            

            3:关闭并保存

            CTRL + X请求nano退出,按Y确认保存配置。

            4:应用新配置

            . ~/.zshrc
            

            5:关闭终端再打开

            您现在可以转到您的项目根目录并输入“typeorm”,这将使用 ts-node 和 node_modules 中的 typeorm-cli。

            【讨论】:

              【解决方案14】:

              我解决了这个问题!

              1. 在根目录下创建pm2.config.js 文件,代码如下:

                 module.exports = {
                   apps: [
                     {
                       name: "app",
                       script: "./build/index.js",
                     },
                   ],
                 };
                
              2. 更改ormconfig.js中的实体路径

                {
                   "type": "postgres",
                   "host": "localhost",
                   "port": 5432,
                   "username": "postgres",
                   "password": "password",
                   "database": "db_name",
                   "synchronize": false,
                   "logging": true,
                   "entities": [
                      "../src/entity/**/*.ts",  ===>>> this line is important
                      "./build/entity/**/*.js"
                   ],
                   "migrations": [
                      "../src/migration/**/*.ts",===>>> this line is important
                      "./build/migration/**/*.js"
                   ],
                   "subscribers": [
                      "../src/subscriber/**/*.ts",===>>> this line is important
                      "./build/subscriber/**/*.js"
                   ],
                   "cli": {
                      "entitiesDir": "src/entity",
                      "migrationsDir": "src/migration",
                      "subscribersDir": "src/subscriber"
                   }
                }
                
              3. tsconfig.json 代码如下:

                {
                   "compilerOptions": {
                      "lib": [
                         "es5",
                         "es6"
                      ],
                      "target": "es5",
                      "module": "commonjs",
                      "moduleResolution": "node",
                      "outDir": "./build",
                      "emitDecoratorMetadata": true,
                      "experimentalDecorators": true,
                      "sourceMap": true,
                      "esModuleInterop": true
                   }
                }
                
              4. 运行以下命令进行生产:

                tsc  =>> This command generate "build" folder
                
              5. pm2 中运行以下命令以运行节点应用程序:

                tsc && pm2 start pm2.config.js
                

              现在使用此解决方案 2 天后,我的带有 node express 和 typeorm 的应用程序可以正常工作了! 此外,我的应用程序正在使用 pm2 在 linux 和 nginx 上运行。

              【讨论】:

              • 我仅将此解决方案用于生产。为了开发,我将“../src/entity/**/*.ts”更改为“src/entity/**/*.ts”,然后运行“nodemon --exec ts-node./src/index.ts” " 并且有效
              【解决方案15】:

              支持迁移的配置:

              // FILE: src/config/ormconfig.ts
              
              const connectionOptions: ConnectionOptions = {
                
                // Other configs here
              
                // My ormconfig isn't in root folder
                entities: [`${__dirname}/../**/*.entity.{ts,js}`],
                synchronize: false,
                dropSchema: false,
                migrationsRun: false,
                migrations: [getMigrationDirectory()],
                cli: {
                  migrationsDir: 'src/migrations',
                }
              }
              
              function getMigrationDirectory() {
                  const directory = process.env.NODE_ENV === 'migration' ? 'src' : `${__dirname}`;
                  return `${directory}/migrations/**/*{.ts,.js}`;
              }
              
              export = connectionOptions;
              
              // FILE package.json
              
              {
                // Other configs here
              
                "scripts": {
                  "typeorm": "NODE_ENV=migration ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config src/config/database.ts",
                  "typeorm:migrate": "npm run typeorm migration:generate -- -n",
                  "typeorm:run": "npm run typeorm migration:run",
                  "typeorm:revert": "npm run typeorm migration:revert"
                }
              }
              

              【讨论】:

                【解决方案16】:

                如果您使用 typescript 编写并使用 tsc 创建一个包含已翻译 js 文件的 dist 文件夹,那么您可能遇到了我的问题,它会在这里得到解决。

                正如docs 中提到的,如果您使用nodemon server.js,那么您将从 js 的角度访问实体,它不会识别导入,因为它与 ts 和 es6 相关。但是如果你想从 ts 文件中导入实体,你应该运行 ts-node server.ts!

                我个人认为前者node server.js更安全,因为它更接近真实案例应用。

                !!!然而 !!!要非常小心,因为如果您更改实体的名称,您必须删除 dist 文件夹并重建它,否则它将引发错误或意外工作。 发生错误是因为tsc 将尝试翻译更改和创建的 ts 文件并保留已删除的文件以便它可以更快地运行!

                我希望它有所帮助,因为它肯定会在未来帮助我,因为我几乎可以肯定我会再次忘记它!

                【讨论】:

                  【解决方案17】:

                  我也遇到了同样的问题。唯一的区别是我的项目使用 .env 文件而不是 ormconfig.json

                  这就是我的 .env 文件配置的样子。

                  TYPEORM_ENTITIES = src/modules/*.entity.ts
                  TYPEORM_MIGRATIONS = src/migrations/*.entity.ts
                  TYPEORM_MIGRATIONS_RUN = src/migrations
                  TYPEORM_ENTITIES_DIR = src/modules
                  TYPEORM_MIGRATIONS_DIR = src/migrations
                  

                  并使用命令运行

                  nest start
                  

                  问题似乎是 TypeORM 不接受打字稿文件形式的实体。

                  有两种方法可以用来解决这个问题。

                  1. 使用node-ts 代替nest start 解决了问题,无需修改实体文件的路径。据我了解,node-ts 将毫无问题地处理 src 文件夹中的打字稿文件。

                  2. 将实体和迁移文件路径改为指向dist文件夹中编译好的js文件。

                     TYPEORM_ENTITIES = dist/modules/*.entity.js
                     TYPEORM_MIGRATIONS = dist/migrations/*.entity.js
                     TYPEORM_MIGRATIONS_RUN = dist/migrations
                     TYPEORM_ENTITIES_DIR = dist/modules
                     TYPEORM_MIGRATIONS_DIR = dist/migrations
                    

                    通过这种方法,我可以毫无问题地使用nest start

                  【讨论】:

                    【解决方案18】:

                    我仅将此解决方案用于生产。 为了开发,我将"../src/entity/**/*.ts" 更改为"src/entity/**/*.ts",然后运行此命令:"nodemon --exec ts-node ./src/index.ts" 并且它可以工作 -

                    【讨论】:

                      【解决方案19】:

                      这里接受的答案 (https://stackoverflow.com/a/59607836/2040160) 是帮助我生成和运行迁移,而不是运行 NestJS 项目。我npm run start:dev时遇到了和作者一样的错误。

                      对我有用的是只用原生 JavaScript 生成迁移文件。 我的ormconfig,json 文件:

                      { 
                        "type": "cockroachdb",
                        "host": "localhost",
                        "port": 26257,
                        "username": "root",
                        "password": "",
                        "database": "test",
                        "entities": ["dist/**/*.entity{.ts,.js}"],
                        "migrations": ["migration/*.js"],
                        "synchronize": false,
                        "cli": {
                          "migrationsDir": "migration"
                        }
                      }
                      

                      package.json中的脚本:

                      "typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js"
                      

                      以及我用来生成迁移的命令:

                      npm run typeorm migration:generate -- -o -n init
                      

                      -o 标志将以原生 JavaScript 输出迁移。

                      【讨论】:

                      • 这不是解决方案。您刚刚创建了一个解决方法并假装问题已解决。
                      【解决方案20】:

                      错误出现在您的 ormconfig.json 文件中。检查您的代码在哪里搜索实体、迁移、订阅者。在开发、测试环境中,它将在您的 src/entities src/migrations src/subscribers 中搜索它们。但是在生产环境中,如果您保持原样,它仍然会在同一路径中搜索,而不是在您的构建路径 dist/src/entities 等中搜索...... ;)

                      【讨论】:

                        猜你喜欢
                        • 2021-09-15
                        • 2021-12-03
                        • 2020-09-13
                        • 2023-02-08
                        • 2021-06-30
                        • 2021-01-05
                        • 2019-11-13
                        • 1970-01-01
                        相关资源
                        最近更新 更多