🔌

バニラTS(JS)でインターフェース分離の原則から状態を管理するTips

2023/10/09に公開

目次

  1. 概要
  2. 実装
  3. まとめ

概要

ReactやVue.jsを使用しているとコンポーネント内の状態を定義して更新するということが簡単に実装可能であり、どこで管理されているかも分かりやすくなります。

しかし、そのようなライブラリやフレームワークを使用していない場合、決まったルールを定めない限り、状態が管理されずに状態を更新するコードが散らばってしまいます。

そこで今回は非常に短いですが、SOLIDの原則の1つであるインターフェース分離の原則を使用して、ViteのVanillaTSの初期コードにあるカウンターの状態管理を行います。

実装

state.ts
export interface Counter {
  count: number;
  readonly addNumber: number;
}

interface State extends Counter {
  readonly limit: number;
}

export const State: State = {
  count: 100,
  limit: 1000,
  addNumber: 2,
};
counter.ts
import { Counter } from "./state";

export function setupCounter(element: HTMLButtonElement, state: Counter) {
  const setCounter = (count: number) => {
    state.count = count;
    element.innerHTML = `count is ${state.count}`;
  };
  element.addEventListener("click", () =>
    setCounter(state.count + state.addNumber)
  );
  setCounter(state.count);
}
main.ts
import { State } from "./state.ts";
import { setupCounter } from "./counter.ts";

/**
 * 省略
 */

setupCounter(document.querySelector<HTMLButtonElement>("#counter")!, State);

まとめ

今回のコードでは、まずstate.tsStateオブジェクトにて状態を宣言しています。

setupCounter関数はCounter型の引数を取ることで、この関数は状態となるStateオブジェクトではなくともCounterインターフェースを実装するオブジェクトであれば、実行可能な関数となっています。

ここで、setupCounter関数のためのインターフェースであるCounterを個別に用意しStateがそれを実装することで、インターフェースがクライアント毎に分離されインターフェースの責務が単一となり、インターフェース分離の原則に沿った形となります。

もし、状態を参照する関数が増えた場合はStateが実装するインターフェースをその関数のために用意し実装する形となります。

Discussion