TSyringe
TypeScript で依存性注入(Dependency Injection, DI)を使いたいときに便利なのが、tsyringe というライブラリ。 @injectable()
や @inject()
といったデコレータを使って、簡単にサービスの差し替えやテストが可能。
@injectable()
@injectable()
は「このクラスは DI コンテナによってインスタンス化しても OK」というマーク。 tsyringe では、DI に使いたいクラスには必ずこのデコレータを付ける。
@inject
@inject(...)
は、「ここにはこのサービスを注入する」と tsyringe に伝えるデコレータ。
通常、識別子(トークン)として文字列を使い、コンテナに登録した内容をここで受けとる。
実装例:多言語あいさつサービス
以下のコードでは、英語・日本語・モックの 3 種類の GreetingService
をDI
で切り替え可能にしている。
ts
import 'reflect-metadata'
import { injectable, inject, container } from 'tsyringe'
interface GreetingService {
getGreeting(name: string): string
}
@injectable()
class EnglishGreetingService implements GreetingService {
getGreeting(name: string): string {
return `Hello, ${name}!`
}
}
@injectable()
class JapaneseGreetingService implements GreetingService {
getGreeting(name: string): string {
return `こんにちは、${name}さん!`
}
}
@injectable()
class MockGreetingService implements GreetingService {
getGreeting(name: string): string {
return `Mock greeting for ${name}.`
}
}
const TOKENS = {
GreetingService: 'GreetingService',
} as const
@injectable()
class MainController {
constructor(
@inject(TOKENS.GreetingService)
private greetingService: GreetingService
) {}
showGreeting(name: string) {
console.log(this.greetingService.getGreeting(name))
}
}
function setup(serviceType: 'english' | 'japanese' | 'mock') {
switch (serviceType) {
case 'english':
container.register<GreetingService>(TOKENS.GreetingService, {
useClass: EnglishGreetingService,
})
break
case 'japanese':
container.register<GreetingService>(TOKENS.GreetingService, {
useClass: JapaneseGreetingService,
})
break
case 'mock':
container.register<GreetingService>(TOKENS.GreetingService, {
useClass: MockGreetingService,
})
break
}
}
setup('english')
const controller = container.resolve(MainController)
controller.showGreeting('Alice')
// Hello, Alice!
setup('japanese')
const controller2 = container.resolve(MainController)
controller2.showGreeting('太郎')
// こんにちは、太郎さん!
setup('mock')
const controller3 = container.resolve(MainController)
controller3.showGreeting('Alice')
// Mock greeting for Alice.
container.register
tsyringe
依存性注入コンテナにサービスを登録するための関数です。<T>
はインターフェース(型)で、ここでは GreetingService
型の依存を注入する事を指定。
useClass
実際に使うクラス(実装)。このクラスをnew
して GreetingService
として注入するよう登録する。
ts
container.register<GreetingService>(TOKENS.GreetingService, {
useClass: EnglishGreetingService,
})
その他
@singleton()
tsyringe
の依存性注入(DI)コンテナに、このクラスは1回だけインスタンス化して、ずっと同じインスタンス使用することを伝える。