仕事でJestを使っているのですが、テストに合計5分以上かかるようになってきました。
そこでテストの時間を短縮するために「swc」というRust製のトランスパイラを使うことにしました。
ただ、swcとTypeORM(というか中で使われているデコレータ周り)の相性が悪いらしく、普通に導入しただけでは動きませんでした。
そこで色々四苦八苦した結果、「これをやったら動くようになったよ」というのをメモしておきたいと思います。
- バージョンメモ
├── @swc/jest@0.2.24
├── ts-node@10.9.1
├── typeorm@0.2.45
├── typescript@4.8.2
└── webpack@5.75.0
entityの中で独自の型を使う場合は、@Column({ type: “varchar” })みたいにカラムのtypeを指定するようにする
結論から書くと、以下ではダメで、
❌Bad
type Gender = "MAN" | "WOMAN"; @Entity() export class User { @Column({ unique: true, primary: true }) readonly id: string; @Column() name: string; @Column() age: string; @Column() 👈👈👈👈👈👈👈ここがダメ gender: Gender; @CreateDateColumn() readonly createdAt: Date; }
以下のように書くと、1つのエラーを解消できました。
✅Good
type Gender = "MAN" | "WOMAN"; @Entity() export class User { @Column({ unique: true, primary: true }) readonly id: string; @Column() name: string; @Column() age: string; @Column({ type: "varchar" }) 👈👈👈👈👈👈こうすると良い gender: Gender; @CreateDateColumn() readonly createdAt: Date; }
よくわかっていないのですが、Entityの中でプリミティブ型じゃない独自の型を使用していると、型をうまく解決できずに全部undefinedになるらしいです。
(これはswc、reflect-metadata、TypeORMというパッケージいずれかの問題ぽいですがよく分かってません。。)
結果、TypeORMがundefinedを許してくれないのでエラーになるらしいので
undefinedになるかもしれないカラムに、こういうデータ型でカラムを作ってくれという指示をしておくと、undefinedでも通るようになる・・・みたいな感じぽいです。
②リレーションの()=>エンティティ名, (エンティティ)=>エンティティ.カラム名 みたいな書き方をやめて、文字列を直接書くようにする
結論から書くと、以下ではダメで、
❌Bad
type Gender = "MAN" | "WOMAN"; @Entity() export class User { @Column({ unique: true, primary: true }) readonly id: string; @Column() name: string; @Column() age: string; @Column({ type: "varchar" }) gender: Gender; @CreateDateColumn() readonly createdAt: Date; @OneToMany(() => Post, (Post) => Post.createdBy) 👈👈👈👈👈ここがダメ posts: Post[]; } @Entity() export class Post { @Column({ unique: true, primary: true }) readonly id: string; @Column() title: string; @Column() content: string; @CreateDateColumn() readonly createdAt: Date; @ManyToOne(() => User, (User) => User.posts) 👈👈👈👈👈ここがダメ createdBy: User; }
以下のように書くと、1つのエラーを解消できました。
✅Good
type Gender = "MAN" | "WOMAN"; @Entity() export class User { @Column({ unique: true, primary: true }) readonly id: string; @Column() name: string; @Column() age: string; @Column({ type: "varchar" }) gender: Gender; @CreateDateColumn() readonly createdAt: Date; @OneToMany("Post", "createdBy") 👈👈👈👈👈こうすると良いらしい posts: Post[]; } @Entity() export class Post { @Column({ unique: true, primary: true }) readonly id: string; @Column() title: string; @Column() content: string; @CreateDateColumn() readonly createdAt: Date; @ManyToOne("User", "posts") 👈👈👈👈👈👈こうすると良いらしい createdBy: User; }
よくわかっていないのですが、swcはファイルを1つずつトランスパイルをしていく(?)ので、循環参照が起こる書き方をしていると「循環参照してんぞ」なエラー(before initializeみたいなエラー)が出ちゃうらしい。
なので循環参照しないような書き方でリレーションを書くようにします。
そのための書き方が用意されてるぽかったので、これで書きなおしたらエラーが出なくなりました↓。
https://github.com/typeorm/typeorm/issues/4190
そんな感じでした。
おわり
コメント