TypeORM实体在NESTJS中 - 无法在模块外部使用导入语句。

132

使用 'nest new' 命令开始新项目。 在添加实体文件之前运行良好。

遇到以下错误:

import { Entity,Column,PrimaryGeneratedColumn } from 'typeorm';

^^^^^^

SyntaxError:无法在模块外部使用导入语句

我错过了什么?

将实体添加到模块中:

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
@Preston,您能详细说明一下您的意思吗?您是否需要为常用共享文件创建一个模块? - Joshua de Leon
你是从你的linter还是编译中得到错误信息的?你有这个新文件吗?它在你的src目录下吗?如果你正在使用TypeORM,你能展示一下在AppModuleimports数组中的TypeOrmModule导入吗?也许我们看不到配置中的某些问题。 - Jay McDoniel
更新帖子,包含实体导入信息。 - Anton
28个回答

208
我的假设是您有一个带有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 的文件(.js 或在 TypeormModule.forRoot() 的传递参数中)中完成的。如果您使用的是 ormconfig.json,则应该使用

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

这样你就可以使用编译后的js文件,并且没有机会在你的代码中使用ts文件。

或者使用

autoLoadEntities: true,

98
但这真是一团糟。一个 TypeScript ORM 不接受 TypeScript 迁移文件... - Matteo
3
Deno是唯一的本地TypeScript代码运行器。虽然TypeORM使用TypeScript,但仍与Node和JavaScript运行时一起工作。也许可以对其进行改进,接受ts文件并在幕后将其编译为JavaScript,然后删除它们,以便最终用户不会看到它们,但这需要在TypeORM git存储库上提出问题。 - Jay McDoniel
2
实际上完整的一行应该是 "entities": ["dist/**/*.entity.js"], 因为这是json语法。 - Nurullah Macun
19
我完全同意,不得不深入转换后的JS来实现所有这些混乱的操作确实很荒谬。 - Patrick
3
Github上的问题#4283详细解释了为什么应该使用JavaScript从Dist文件夹中读取实体。这是我在根文件夹中更改的神奇代码行,你也可以尝试并查看。entities: ['dist/**/*.entity.js']就是解决方案。 - Niyongabo Eric
这节省了我很多时间。谢谢@JayMcDoniel - rosinghal

60
在TypeORM文档中,我找到了一个特定的Typescript部分。
这个部分说:

Install ts-node globally:

npm install -g ts-node

Add typeorm command under scripts section in package.json

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

Then you may run the command like this:

npm run typeorm migration:run

If you need to pass parameter with dash to npm script, you will need to add them after --. For example, if you need to generate, the command is like this:

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"
    }
}

接下来你可以运行生成命令。


22.04.23 我不得不运行这个命令: npm run typeorm migration:generate -- migrationNameHere -d ./src/data-source.ts - Robert Rendell

25

正如Jay McDoniel在他的回答中所解释的那样,问题似乎出在ormconfig.json文件中实体文件的模式匹配上:可能会从JavaScript文件中导入TypeScript文件(可能是之前编译过的TypeScript文件)。

只需在ormconfig.json中删除现有的ts glob模式即可。这样TypeORM将仅加载JavaScript文件。实体文件的路径应相对于执行node命令的工作目录。

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

src 应该改为 dist,因为在将代码转换为 JavaScript 后,可运行的代码就在那里了。 - Jay McDoniel
花了我一些时间:在运行时,代码将从“dist”(分发)文件夹中运行。包含数据库模型的*.entity.ts文件将由TypeOrm转换为.js文件。因此,实体条目应指向“dist”文件夹下的*.entity.js。谢谢大家。救了我的一天。 - Yazid

10

在我的情况中,按照官方文档所述,在 ormconfig.json 文件中定义 entities 属性解决了这个问题。

// This is your ormconfig.json file

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

8

我在tsconfig.json文件中做了以下更改:

"module": "es6"
至:
"module": "commonjs",

它对我有帮助。


1
非常感谢。被采纳的答案很好,但这正是我缺少的那一部分。 - Vulgo Alias

5

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

我在我的IDE自动导入错误的包后遇到了这个问题。从导入中删除 '/browser' 即可解决。


1
如果有人需要帮助,我也遇到了完全相同的问题,在一个nestjs和typeorm项目中。只需要将import { Unique } from 'typeorm/browser';更改为import { Unique } from 'typeorm';即可解决。 - Jay

5

这是我修复它的方法。使用单个配置文件,我可以在应用程序启动或使用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

我必须更新“迁移”以匹配您的语法。 - Lahori

4

在使用Node.js、Typescript和TypeORM时,我遇到了这个问题。在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"
  }
}

3
我找到的替代方案是拥有两个ORM配置文件,分别为orm-config.ts和cli-orm-config.ts(您可以随意命名)。
//content of cli-orm-config.ts

import { DataSource, DataSourceOptions } from "typeorm"
import 'dotenv/config'

export const cliOrmConfig: DataSourceOptions = {
    type: 'postgres',
    host: process.env.DATABASE_HOST,
    port: (process.env.PG_DATABASE_PORT as any) as number,
    username: process.env.PG_DATABASE_USER,
    password: process.env.PG_DATABASE_PASSWORD,
    database: process.env.DATABASE_NAME,
    entities: ["src/**/*/*.entity{.ts,.js}"],
    migrations: ["src/**/*/*-Migration{.ts,.js}"]
}

const datasource = new DataSource(cliOrmConfig)

export default  datasource


//content of orm-config.ts, this is the one I use in nest TypeOrmModule.forRoot(ormConfig)

import { DataSource, DataSourceOptions } from 'typeorm';
import 'dotenv/config'


export const ormConfig: DataSourceOptions = {
    type: 'postgres',
    host: process.env.DATABASE_HOST,
    port: (process.env.PG_DATABASE_PORT as any) as number,
    username: process.env.PG_DATABASE_USER,
    password: process.env.PG_DATABASE_PASSWORD,
    database: process.env.DATABASE_NAME,
    entities: ["dist/src/**/*/*.entity{.ts,.js}"]
}

const datasource = new DataSource(ormConfig)

export default  datasource


// My package.json relevant scripts section

"typeorm": "ts-node ./node_modules/typeorm/cli -d ./src/db/cli-orm-config.ts",
"nest:migration:generate": "npm run typeorm migration:generate ./src/db/migrations/Migration",
"nest:migration:run": "npm run typeorm migration:run"


我认为就TypeOrm而言,迁移和cli部分应该与模型加载和其他内容分离;因此需要分开保存两个ORM配置文件。
希望能对某些人有所帮助。

3
与他人的评论一致,完全依赖生成的代码来使其工作似乎有些愚蠢。本人不对此解决方案进行任何贡献,因为它是其他人的仓库,但它确实可以完全使用Typescript进行迁移。它依赖于.env文件中的Typeorm值,而不是ormconfig.json文件,尽管我相信它也可以被转换。我发现这个解决方案对我有很大帮助,让我摆脱了对.js文件的依赖。
以下是该资源库: https://github.com/mthomps4/next-now-test/tree/next-typeorm-example 它如何运作的解释:
除了您平常在.envormconfig.json文件中正确配置的本地主机数据库连接之外,您还需要在ormconfig.json.env文件中正确指定以下内容。
TYPEORM_ENTITIES="entities/*.ts"
TYPEORM_MIGRATIONS="migrations/*.ts"
TYPEORM_ENTITIES_DIR="entities"
TYPEORM_MIGRATIONS_DIR="migrations"

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

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

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

这就是允许 ts-node 正确“捡起” .ts 文件并生成迁移的原因。

这个 npm 脚本(如果使用 .env 文件而不是 ormconfig.json,则 DOTENV 部分才需要)指定要使用那个 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"

我并不百分之百确定所有这些都是必要的(你可以尝试所有行内完成),但对于我而言,它是有效的。基本上,这意味着“在ts-node的上下文中以特定的.env文件和特定的tsconfig调用typrorm cli ”。在某些情况下,你可以跳过这些配置。

最后,这个脚本现在可以运行:

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

因此运行以下命令:

npm run g:migration -- User

你将基于当前已更改的实体自动生成迁移文件!
所以,经过三个嵌套的npm脚本后,我们有了一种非常特定的方法来运行"generate"迁移命令,并使用正确的配置来仅使用TS文件。太好了 - 难怪有些人仍然反对typescript,但幸运的是,这确实有效,上面的示例仓库已经预先配置好了所有内容,如果想尝试它,可以看看它是如何“正常工作”的。

1
谢谢这个;有用的! - kendepelchin

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