Skip to content

TSyringe

 TypeScript で依存性注入(Dependency Injection, DI)を使いたいときに便利なのが、tsyringe というライブラリ。  @injectable()@inject() といったデコレータを使って、簡単にサービスの差し替えやテストが可能。

@injectable()

@injectable() は「このクラスは DI コンテナによってインスタンス化しても OK」というマーク。 tsyringe では、DI に使いたいクラスには必ずこのデコレータを付ける。

@inject

@inject(...) は、「ここにはこのサービスを注入する」と tsyringe に伝えるデコレータ。
通常、識別子(トークン)として文字列を使い、コンテナに登録した内容をここで受けとる。

実装例:多言語あいさつサービス

 以下のコードでは、英語・日本語・モックの 3 種類の GreetingServiceDIで切り替え可能にしている。

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回だけインスタンス化して、ずっと同じインスタンス使用することを伝える。