10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Typescript DIフレームワーク InversifyJS vs. TSyringe

Posted at

概要

とある経緯でTypescriptでDIフレームワークについて調べることがあったのでそのまとめ。
比較対象として、InversifyJSとTSyringeの2つを触ってみたのでその備忘録。

1.InversifyJS

スクリーンショット 2020-03-09 22.56.15.png

READMEに書かれている通り強力なDIフレームワーク。TypescriptのDIフレームワークで調べると結構これが出てくるし、実際にgithub starの数も他と比べるとかなり多い。

使い方

DIされる側は以下のようにインターフェースの実装クラスに@Injectable()を付ける。

Employee.ts
// インターフェース
export interface Employee {
    work(): void;
}
BoardGameLover.ts
import { Employee } from './Employee';
import { injectable } from 'inversify';
import 'reflect-metadata';

// 実装クラス
@injectable()
export class BoardGameLover implements Employee {

    work(): void {
        console.log('ずっとボードゲームを遊んでいる.');
    }

}

利用側では@Injectをつける。

import { Employee } from './Employee';
import { Shop } from './Shop';
import { injectable, inject } from 'inversify';
import { TYPES } from './types';

@injectable()
export class BoardGameShop implements Shop {
    private employee: Employee;

    // コンストラクタインジェクション
    constructor(@inject(TYPES.Employee) employee: Employee) {
        this.employee = employee;
    }

    watchEmployee() {
        this.employee.work();
    }
}

@Injectに渡しているTYPES.EmployeeはSymbolを渡していて、別途types.tsというファイルに宣言している。これによってDIされるオブジェクトをリテラルで書かずにSymbolでやりとりしている。

types.ts
const TYPES = {
    Employee: Symbol.for('Employee'),
    Shop: Symbol.for('Shop')
}

export { TYPES }

DIコンテナに登録するオブジェクトは以下のようなConfigファイルにまとめて記載をし、ここでインターフェース、シンンボル、DIされる実クラスの紐付けを行っている。

inversify.config.ts
import { BoardGameLover } from './BoardGameLover';
import { Employee } from './Employee';
import { BoardGameShop } from './BoardGameShop';
import { Shop } from './Shop';
import { Container } from "inversify";
import { TYPES } from "./types";

const myContainer = new Container();
myContainer.bind<Shop>(TYPES.Shop).to(BoardGameShop);
myContainer.bind<Employee>(TYPES.Employee).to(BoardGameLover);

export { myContainer };

コンテナから取り出すときは以下のようなかたち

const shop = myContainer.get<Shop>(TYPES.Shop);

感触

READMEに書かれている利用法はシンプルだが、この他にもプロパティインジェクション(フィールドインジェクション)があったり、ContainerクラスのAPIが充実していたりとかなり多機能。バックエンドをクリーンアーキテクチャでがっつり作るとかには向いてそう。

しばらく前からメンテされてなさそうな雰囲気が残念(2020/3現在)。ロゴがかっこいい。

2. TSyringe

スクリーンショット 2020-03-12 21.01.29.png

マイクロソフトが出しているDIフレームワーク。InversifyJSに比べるとこちらはかなり軽量で、コンストラクタインジェクションにフォーカスを絞っている。機能もドキュメントもとにかく小さい。

使い方

基本的なアノテーションはほぼ同じで、@injectable, @Injectを使って定義をする。

DIするオブジェクト

Employee.ts
// インターフェース
export interface Employee {
    work(): void;
}
BoardGameLover.ts
import { Employee } from "./Employee";
import {injectable} from "tsyringe";

// 実装クラス
@injectable()
export class BoardGameLover implements Employee {

    work(): void {
        console.log("ずっとボードゲームを遊んでいる.");
    }

}

利用側

import { Shop } from './Shop';
import { Employee } from "./Employee";
import { injectable, inject } from "tsyringe";

@injectable()
export class BoardGameShop implements Shop{
    employee: Employee;

    // コンストラクタインジェクション
    constructor(@inject("Employee") employee: Employee) {
        this.employee = employee;
    }

    watchEmployee() {
        this.employee.work();
    }
}

コンテナの宣言は以下のような感じ。Inversifyと違いインターフェースを被っているコンポーネントのコンテナ登録はリテラルで行われるので保守しやすさを意識するなら別途types.tsみたいなファイルを宣言するのが良さそう。

main.ts
import "reflect-metadata";
import {container} from "tsyringe";
import { Employee } from "./Employee";
import { BoardGameLover } from "./BoardGameLover";
import { Shop } from "./Shop";
import { BoardGameShop } from "./BoardGameShop";

// コンテナ定義
container.register("Employee", {useClass: BoardGameLover})
container.register("Shop", {useClass: BoardGameShop})

const shop: BoardGameShop = container.resolve("Shop")

console.log("店員の様子をチェック.")
shop.watchEmployee();

感触

基本的なDIの仕方はInversifyJSと同じで、こっちのほうがより提供機能が絞られている。プロパティインジェクションとかは明示的にやらないと宣言されていたり、本当にシンプルなDIフレームワークを目指しているようには見える。
ドキュメントはほとんどなくて、実質READMEだけという状態。これから伸びていけば充実してくかもしれない。とりあえずコンストラクタインジェクションが使えるようにしたい、であればこちらのほうがいいかもしれない。

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?