上級者向け!TypeScriptでシングルトンパターンを使いこなすテクニック

2024-04-02

TypeScriptでシングルトンパターンを実装するには、いくつかの方法があります。

コンストラクタをprivateにする

これは最も簡単な方法です。クラスのコンストラクタをprivateにすることで、外部からインスタンスを作成することができなくなります。

class Singleton {
  private constructor() {}

  private static instance: Singleton;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true

クラス変数を使う

この方法は、クラス変数を使ってインスタンスを保存します。

class Singleton {
  private static instance: Singleton | null = null;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true

モジュールを使う

export class Singleton {
  private constructor() {}

  private static instance: Singleton | null = null;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true

シンボルを使う

const singletonSymbol = Symbol();

export class Singleton {
  private constructor() {}

  private static instance: Singleton | null = null;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true

シングルトンパターンを使うメリット

  • オブジェクトの数が少なくなる
  • オブジェクトの状態を管理しやすくなる
  • オブジェクトへのアクセスが一元化される
  • テストが難しい
  • 柔軟性に欠ける
  • 依存関係の注入が難しい



class Singleton {
  private constructor() {}

  private static instance: Singleton;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true
class Singleton {
  private static instance: Singleton | null = null;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true
export class Singleton {
  private constructor() {}

  private static instance: Singleton | null = null;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true
const singletonSymbol = Symbol();

export class Singleton {
  private constructor() {}

  private static instance: Singleton | null = null;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true



シングルトンパターンを実装する他の方法

遅延初期化

この方法は、インスタンスが実際に必要になるまで作成しないというものです。

class Singleton {
  private constructor() {}

  private static instance: Singleton | null = null;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      // ここでインスタンスを作成する
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2); // true

ファクトリー関数を使う

この方法は、ファクトリー関数を使ってインスタンスを作成するというものです。

function createSingleton(): Singleton {
  if (!Singleton.instance) {
    // ここでインスタンスを作成する
    Singleton.instance = new Singleton();
  }

  return Singleton.instance;
}

const singleton1 = createSingleton();
const singleton2 = createSingleton();

console.log(singleton1 === singleton2); // true

デコレータを使う

この方法は、デコレータを使ってシングルトンパターンを実装するというものです。

function singleton(constructor: Function) {
  return class Singleton {
    private static instance: Singleton | null = null;

    public static getInstance(): Singleton {
      if (!Singleton.instance) {
        // ここでインスタンスを作成する
        Singleton.instance = new constructor();
      }

      return Singleton.instance;
    }
  };
}

@singleton
class MySingleton {
  // ...
}

const singleton1 = MySingleton.getInstance();
const singleton2 = MySingleton.getInstance();

console.log(singleton1 === singleton2); // true

singleton typescript


TypeScript インターフェースで readonly プロパティを定義する方法

TypeScript では、インターフェースを使用してオブジェクトの構造を定義することができます。インターフェースには、オブジェクトが持つべきプロパティと、それぞれのプロパティの型を定義することができます。さらに、readonly 修飾子を使用して、プロパティを 読み取り専用 にすることができます。つまり、そのプロパティの値は、一度設定されたら 変更できない ことを意味します。...


JavaScript・TypeScriptで正規表現を使いこなす!サンプルコードで徹底解説

正規表現は、文字列のパターンを記述するための強力なツールです。電話番号、メールアドレス、URLなどの複雑なパターンを抽出したり、文字列の操作や検証を行ったりする際に役立ちます。TypeScriptでのRegExpの利用TypeScriptでは、JavaScriptと同様に2つの方法でRegExpオブジェクトを生成できます。...


TypeScriptで開発をもっと快適に!.tsと.d.tsファイルを使いこなすためのガイド

*1. .tsファイル:TypeScriptソースコードを含むファイルです。変数、関数、クラス、インターフェースなどのプログラム要素を定義します。プログラミングロジックを実装します。ブラウザやNode. jsで直接実行することはできません。...


TypeScript:ジェネリックで再利用可能なコンポーネントや関数を作成する

typeof 演算子は、オペランドの型を取得するために使用されます。as キーワードを使用して、変数を特定の型にキャストすることができます。注意: as キーワードは、型の安全性チェックをバイパスするため、慎重に使用してください。型ガードは、変数の型が特定の型かどうかを確認するために使用されます。...


TypeScriptで型安全性を高めるためのベストプラクティス

このとき、Person 型は、Person クラスのインスタンスのみを値として持つ型となります。つまり、以下のコードは有効です:一方、any 型は、あらゆる型の値 を持つことができます。つまり、型安全性がない型です。以下のようなコードは有効です:...