← 解説「カスタムプロバイダ — useValue / useFactory / useClass」に戻る
サンプルコードで身につける: カスタムプロバイダ — useValue / useFactory / useClass
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1クラス省略形の正体は useClass
providers にクラスを並べるだけの書き方が、provide と useClass を組にした省略形であることを示します。両者はまったく同じ意味で、フルの形を知っておくと次の useValue / useFactory への発展が理解しやすくなります。
import { Module } from "@nestjs/common";
import { UsersService } from "./users.service";
@Module({
// この2つはまったく同じ意味
providers: [
UsersService, // 省略形
// { provide: UsersService, useClass: UsersService }, // フルの形
],
})
export class UsersModule {}
2useValue で固定値を注入する
設定オブジェクトや定数のような「生成不要の固定値」は useValue で注入します。トークンに文字列を使った場合、受け取る側は @Inject("トークン名") を明示する必要がある点が、クラスをトークンにする場合との違いです。
import { Module, Injectable, Inject } from "@nestjs/common";
@Injectable()
export class MailService {
// 文字列トークンは @Inject で明示して受け取る
constructor(@Inject("MAIL_CONFIG") private cfg: { from: string }) {}
sender() {
return this.cfg.from;
}
}
@Module({
providers: [
{ provide: "MAIL_CONFIG", useValue: { from: "noreply@example.com" } },
MailService,
],
})
export class MailModule {}
3useFactory の本質をプレーンTSで再現
useFactory の「トークンごとにファクトリ関数で値を生成し、inject で指定した依存も渡す」という核心を、デコレータなしの簡易コンテナで再現した実行例です。useValue と useFactory の両方を1つのコンテナで解決する流れが追えます。
TypeScript
4useFactory の解決順序を再現
useFactory が inject の依存を先に解決してから自分を生成する、という順序を生成ログで可視化した実行例です。登録順ではなく依存関係に沿って組み立てられることが、出力されるログの並びから確認できます。
TypeScript
5実務: 環境ごとに useClass で実装を差し替える
本番では本物の決済クライアント、開発ではログを出すだけの偽実装、というように環境変数で実装を丸ごと差し替える実務例です。注入側は共通のインターフェースしか知らないため、差し替えても呼び出しコードは一切変わりません。
import { Module } from "@nestjs/common";
// 注入側はこのインターフェースだけに依存する
export interface PaymentClient {
charge(amount: number): Promise<string>;
}
export class StripePaymentClient implements PaymentClient {
async charge(amount: number) {
return "stripe:" + amount; // 本物の決済 API を叩く
}
}
export class FakePaymentClient implements PaymentClient {
async charge(amount: number) {
return "fake:" + amount; // 開発用。実際には課金しない
}
}
@Module({
providers: [
{
provide: "PAYMENT_CLIENT",
// 環境変数で実装を丸ごと差し替える(呼び出し側は無変更)
useClass:
process.env.NODE_ENV === "production"
? StripePaymentClient
: FakePaymentClient,
},
],
exports: ["PAYMENT_CLIENT"],
})
export class PaymentModule {}