使用nestjs编写后端服务,免不了要访问数据库,一般我们是使用TypeORM来访问
Entity A 引用 Entity B,Entity B 又引用 Entity A → 编译/运行时爆炸
ReferenceError: Cannot access 'User' before initialization
“把类留给自己,把名字留给对方”
- 自己内部用
import type 拿类型 - 对方用 字符串 或 延迟箭头 去解析,不形成顶层 import 环
目录结构
src/
├─ entity/
│ ├─ user.ts
│ └─ post.ts
└─ index.ts
1
2
3
| npm i typeorm reflect-metadata sqlite3
npm i -D typescript ts-node
npx tsc --init
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import type { Post } from './post'; // ① 只拿类型,不拿实现
@Entity()
export class User {
@PrimaryGeneratedColumn()
id!: number;
@Column()
name!: string;
// ② 字符串 + 泛型:TypeORM 运行时用 'Post',TS 编译时用 Post 类型
@OneToMany<Post>('Post', p => p.author)
posts!: Post[];
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import type { User } from './user';
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id!: number;
@Column()
title!: string;
// ③ 同样套路
@ManyToOne<User>('User', u => u.posts, { onDelete: 'CASCADE' })
author!: User;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| import 'reflect-metadata';
import { DataSource } from 'typeorm';
import { User } from './entity/user';
import { Post } from './entity/post';
const AppDataSource = new DataSource({
type: 'sqlite',
database: ':memory:',
entities: [User, Post],
synchronize: true,
logging: false,
});
async function main() {
await AppDataSource.initialize();
const user = await AppDataSource.manager.save(User, { name: 'Alice' });
await AppDataSource.manager.save(Post, { title: 'Hello', author: user });
const posts = await AppDataSource.manager.find(Post, { relations: ['author'] });
console.log(posts); // 成功打出关联数据
await AppDataSource.destroy();
}
main();
|
1
2
| npx ts-node src/index.ts
# 输出: [ Post { id: 1, title: 'Hello', author: User { id: 1, name: 'Alice' } } ]
|
无报错,循环依赖已消失。
| 场景 | 写法 |
|---|
| 自己要用对方类型 | import type { Other } from './other' |
| 装饰器里引用对方 | @OneToMany<Other>('Other', o => o.xxx) 或 @ManyToOne(() => Other, …) |
| 绝不出现 | import { Other } from './other' 同时又被对方 import |
记住 “类型归 TS,名字归 ORM”,循环依赖永远说再见。