たかぎとねこの忘備録

プログラミングに関する忘備録を自分用に残しときます。マサカリ怖い。

NestJSでモジュール間の循環依存を解消する方法

UsersModuleimports配列に直接AuthModuleクラスを追加したい。

// src/users/users.module.ts

@Module({
  imports: [AuthModule],
  providers: [UsersService, PrismaService],
  controllers: [UsersController],
  exports: [UsersService],
})
export class UsersModule {}

しかし、AuthModuleクラス側でもUsersModuleクラスを参照している場合がある。

// src/auth/auth.module.ts

@Module({
  imports: [
    UsersModule,
    JwtModule.register({
      secret: jwtConstants.secret,
      signOptions: { expiresIn: '60s' },
    }),
  ],
  providers: [AuthService, JwtStrategy],
  exports: [AuthService],
})
export class AuthModule {}

そして、UsersControllerのコンストラクタでauthServiceを参照している。

// src/users/users.controller.ts
...
constructor(
    private readonly usersService: UsersService,
    private readonly authService: AuthService,
  ) {}
...

authモジュールのjwt.strategy.tsではUsersServiceを参照している。

// src/auth/strategies/jwt.strategy.ts

...
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt-strategy') {
  constructor(private usersService: UsersService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: jwtConstants.secret,
    });
  }
...

このまま実行してしまうと- A circular dependency between modules. Use forwardRef() to avoid it.というエラーが表示される。

なので、参照しているお互いのモジュールのimports配列でforwardRefを使用する。

// src/auth/auth.module.ts

...
@Module({
  imports: [
    forwardRef(() => UsersModule),
...
// src/users/users.module.ts

...
@Module({
  imports: [forwardRef(() => AuthModule)],
...

参考

typescript - The module at index [1] is of type "undefined". Check your import statements and the type of the module - Stack Overflow