NestJS は文字列のトークンを実体クラスに置き換えて DI することができる。
これを使ってクラス間をインターフェースで結びつけることができる。
インターフェースの定義
以下UsersService
というサービスをインターフェースで DI できるようにする例を記載する。
インターフェースを定義する。
src/users/interfaces/users.service.interface.ts
import { CreateUserDto } from "../dto/create-user.dto";
import { UserEntity } from "../entities/user.entity";
export interface IUsersService {
/**
* ユーザを取得する
* @param id ID
*/
findOne(id: string): Promise<UserEntity>;
// 長いので省略
}
実装
export class UsersService implements IUsersService
みたいな感じでインターフェースの実装を行う。
src/users/users.service.ts
import { Inject, Injectable } from "@nestjs/common";
import { TYPES } from "src/types";
import { IUsersRepository } from "./interfaces/users.repository.interface";
import { IUsersService } from "./interfaces/users.service.interface";
// 他のimportは省略
@Injectable()
export class UsersService implements IUsersService {
constructor(
@Inject(TYPES.UsersRepository)
private readonly usersRepository: IUsersRepository
) {}
async findOne(id: string): Promise<UserEntity> {
// 実装する
return await this.usersRepository.findOne(id);
}
// 長いので省略
}
文字列トークンの定義
インターフェースの分だけ定数を定義する。
src/types.ts
export const TYPES = {
UsersRepository: Symbol.for("UsersRepository"),
UsersService: Symbol.for("UsersService"),
TodosRepository: Symbol.for("TodosRepository"),
TodosService: Symbol.for("TodosService"),
LoggerService: Symbol.for("LoggerService"),
AuthService: Symbol.for("AuthService"),
};
モジュールの記載
以下のproviders
のように{provide: <文字列トークン>, useClass: 実体クラス}
で記述する。
src/users/users.module.ts
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { TYPES } from "src/types";
import { UsersRepository } from "./users.repository";
import { UsersService } from "./users.service";
// 他のimportは省略
@Module({
// このモジュールが動くのに必要なモジュールを記述する。
imports: [TypeOrmModule.forFeature([UserEntity])],
// このモジュールが提供するコントローラを記述する。
controllers: [UsersController],
// このモジュール内で使うサービスを記述する。
providers: [
{ provide: TYPES.UsersRepository, useClass: UsersRepository },
{ provide: TYPES.UsersService, useClass: UsersService },
],
// このモジュールが他のモジュールへ提供するサービスを記述する。
exports: [TYPES.UsersService],
})
export class UsersModule {}
DI
コンストラクタにて@Inject()
を使って DI する。
src/users/users.controller.ts
import { Inject } from "@nestjs/common";
import { TYPES } from "src/types";
import { IUsersService } from "./interfaces/users.service.interface";
// 他のimportは省略
@Controller("users")
export class UsersController {
constructor(
@Inject(TYPES.UsersService) private readonly usersService: IUsersService
) {}
// 省略
}