3
2

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.

TSyringeを動かしてみた

Last updated at Posted at 2020-05-03

TSyringeを動かしてみたのでそのメモ

注意 動かしてみた結果と、推測を書いているので誤っている可能性もあります😅

TSyringeとは

Microsoftが開発している Javascript/TypeScript用の軽量DIコンテナです。
コンストラクタインジェクションのみサポートしています。

準備

今回はバージョン4.1.0 を使いました。

動作確認はブラウザ上でコンソールに出力して確認しました。

rem typescript 使うので
yarn add typescript -D

rem tsyringeの準備
yarn add tsyringe reflect-metadata

rem webpackを使う
yarn add webpack webpack-cli webpack-dev-server ts-loader -D

rem 動作確認はブラウザでしたかったので
yarn add html-webpack-plugin -D

rem tsconfig 作る
yarn tsc --init

デコレータを使うのでtsconfig.json の以下の部分の設定を変更します。

tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

webpackの設定周りは省略します。

確認1 injectable を試す

とりあえずシンプルに動かしてみます。

一番末端のクラス

FooService.ts
import { injectable } from "tsyringe";

@injectable()
export default class FooService {

    public constructor() {
        console.log("new FooService()")
    }

    doFoo(value: string) {
        return `${value} : Foo!`
    }
}

FooService を使うクラス

HogeService.ts
import { injectable } from "tsyringe";
import FooService from "./FooService";

@injectable()
export default class HogeService {

    constructor(
        private fooService: FooService
    ) {
        console.log("new HogeService()")
    }

    doHoge(value: string) {
        return `${value} : Hoge!`
    }

    doHogeFoo(value: string) {
        return this.fooService.doFoo(this.doHoge(value))
    }
}

エントリポイント

index.ts
//Reflect API を使うためのPolyfill
import "reflect-metadata";
import { container } from "tsyringe";
import FooService from "./FooService";
import HogeService from "./HogeService";

//FooServiceを実行
console.log("---------")
const fooService = container.resolve(FooService);
console.log(fooService.doFoo("test01"));

//HogeServiceを実行
console.log("---------")
const hogeService = container.resolve(HogeService);
console.log(hogeService.doHogeFoo("test02"))

実行結果は以下のようになります。

---------
new FooService()
test01 : Foo!
---------
new FooService()
new HogeService()
test02 : Hoge! : Foo!

特に何も言うことはないです😀

確認1-2 FooService@injectable() を消してみる

FooService.ts
import { injectable } from "tsyringe";

//@injectable()
export default class FooService {

    public constructor() {
        console.log("new FooService()")
    }

    doFoo(value: string) {
        return `${value} : Foo!`
    }
}

実行結果は先ほどと同じになります。

---------
new FooService()
test01 : Foo!
---------
new FooService()
new HogeService()
test02 : Hoge! : Foo!

確認1-3 HogeService@injectable() を消してみる

FooService@injectable() は復活させておきます。

HogeService.ts
import { injectable } from "tsyringe";
import FooService from "./FooService";

//@injectable()
export default class HogeService {

    constructor(
        private fooService: FooService
    ) {
        console.log("new HogeService()")
    }

    doHoge(value: string) {
        return `${value} : Hoge!`
    }

    doHogeFoo(value: string) {
        return this.fooService.doFoo(this.doHoge(value))
    }
}

これを実行したところ以下のようにエラーになります。

---------
new FooService()
test01 : Foo!
---------
dependency-container.js:210 Uncaught Error: TypeInfo not known for "HogeService"
    at InternalDependencyContainer.construct (dependency-container.js:210)
    at InternalDependencyContainer.resolve (dependency-container.js:91)
以下略

確認1 からわかること

@injectable をつけることで、コンテナからインスタンスを取得するときに、コンストラクタに依存パラメータがあれば、それも解決してくれるようです。

FooService@injectableを消しても動いていたのは、何も依存するものがないからエラーが起きていなかったようです。

このあたりのことはinjectable.tsでパラメータ情報を登録している(のかな?)ことや
dependency-container.tsresolveメソッドのこのあたり およびconstructメソッド
を見れば確認ができます。

確認2 singleton を試す

確認1とほとんど同じですがFooServiceのみ@injectable()@singleton()に変更します。

FooService.ts
import { singleton } from "tsyringe";

//↓ここを変更した。
@singleton()
export default class FooService {

    public constructor() {
        console.log("new FooService()")
    }

    doFoo(value: string) {
        return `${value} : Foo!`
    }
}

HogeService.ts は変更なし(@injectable() はつけています。)

index.ts も変更なしです。

実行結果は以下のようになります。

---------
new FooService()
test01 : Foo!
---------
new HogeService()
test02 : Hoge! : Foo!

new HogeService() の前にあった new FooService() が消えています。

他のDIコンテナと同じように@singleton() をつけると、コンテナ内で一つのインスタンスが再利用されるようです。

singleton.ts を見ると、コンテナにシングルトンとして登録しているようです。

確認3 autoInjectable を試してみる

autoInjectableを使うとコンテナから取り出すのではなくnew するだけで依存関係を解決してくれるようです。(すげぇ)

FooService.ts
import { injectable } from "tsyringe";

@injectable()
export default class FooService {

    public constructor() {
        console.log("new FooService()")
    }

    doFoo(value: string) {
        return `${value} : Foo!`
    }
}

@autoInjectable() を付与したクラスです。注意点としてコンストラクタのパラメータに? をつけます。

AutoHogeService.ts
import { autoInjectable } from "tsyringe";
import FooService from "./FooService";

@autoInjectable()
export default class AutoHogeService {

    constructor(
        // ?をつけておかないと new AutoHogeService() とできずコンパイルエラーになる。
        private fooService?: FooService
    ) {
        console.log("new AutoHogeService()")
    }

    doHoge(value: string) {
        return `${value} : Hoge!`
    }

    doHogeFoo(value: string) {
        return this.fooService!.doFoo(this.doHoge(value))
    }
}
index.ts
import "reflect-metadata";
import AutoHogeService from "./AutoHogeService";

console.log("------");
const autoHogeService1 = new AutoHogeService();
console.log(autoHogeService1.doHogeFoo("test1"));

console.log("------");
const autoHogeService2 = new AutoHogeService();
console.log(autoHogeService2.doHogeFoo("test2"));

実行結果は以下のようになります。

------
new FooService()
new AutoHogeService()
test1 : Hoge! : Foo!
------
new FooService()
new AutoHogeService()
test2 : Hoge! : Foo!

new AutoHogeService() を実行したときに new FooService() も実行されているようです。

auto-injectable.ts を見ても何やらresolve していますね。(詳細は解読できていないのでわかりません..)

おわりに

今回は injectable, singleton, autoInjectable を試してみました。

長くなったのでこの辺で終わります。

続きはこちら

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?