【入門編】Interfaceの「メソッド定義」と関数型プログラミングの境界線 – TypeScript コア・型システムの基礎解析バイブル

TypeScriptの境界線を歩く:Interfaceのメソッド定義 vs 関数型プログラミング

こんにちは。TypeScriptの深淵を覗き込み、日夜コンパイラと対話しているエンジニアです。

TypeScriptを書き始めると、必ず一度は立ち止まるポイントがあります。「オブジェクトのメソッドとして関数を定義すべきか、それとも関数型プログラミングのように独立させるべきか?」という問いです。

一見、どちらも「関数を動かす」という意味では同じに見えますが、実はコンパイラが型を評価する際の「文脈」と、あなたのコードが将来どう変化するかという「拡張性」において、両者は決定的に異なります。

今日は、この「設計の境界線」を、TypeScriptの本質と共に紐解いていきましょう。

—

1. Interfaceのメソッド定義:オブジェクトの「振る舞い」を縛る

Interfaceでメソッドを定義するスタイルは、伝統的なオブジェクト指向の考え方に基づいています。

interface Calculator {
// メソッドシグネチャによる定義
add(a: number, b: number): number;
}

const myCalc: Calculator = {
add: (a, b) => a + b
};

なぜこれを使うのか?

これは「このオブジェクトは、こういう能力(振る舞い)を保証している」という宣言です。
`myCalc`という実体の中に`add`という機能が「内包されている」という強い結合関係が生まれます。

陥りやすい罠:`this`の幻想

実は、Interfaceでメソッドを定義する際、`this`の扱いに注意が必要です。アロー関数で実装すると`this`が固定されてしまい、クラスのインスタンスで期待する動作にならないことがあります。

interface User {
name: string;
greet(): void; // プロパティとして関数を持つ
}

この定義は「`greet`という関数は、実行時に`User`オブジェクトのコンテキストを必要とするかもしれない」という余地を残します。

—

2. 関数型プログラミング的アプローチ:データとロジックの分離

一方で、関数型プログラミングでは、データと処理を完全に切り離します。

type AddFunction = (a: number, b: number) => number;

const add: AddFunction = (a, b) => a + b;

なぜこれを使うのか?

データ構造(型)とロジック(関数)が完全に独立しているため、「疎結合」を実現できます。
このスタイルは、関数を引数として渡したり(高階関数)、合成したりする際に圧倒的な威力を発揮します。

—

3. 判断基準:どう使い分けるべきか?

ここが本題です。現場で迷ったら、以下の「判断の指針」を思い出してください。

A. 「Interfaceのメソッド」を使うべきケース

  • ポリモーフィズムが必要なとき: 複数のクラスが共通のインターフェースを実装し、それらを統一的に扱いたい場合(例:`Shape`インターフェースの`draw()`メソッド)。
  • カプセル化が重要なとき: 内部状態(private変数など)とメソッドが密接に関わっている場合。

B. 「独立した関数」を使うべきケース

  • 純粋関数(Pure Function)を作りたいとき: 同じ入力に対して常に同じ出力を返し、外部の状態に依存しない処理。
  • Tree Shaking(不要なコードの削除)を最適化したいとき: モジュールバンドラーは、オブジェクトのメソッドよりも独立した関数の方が、使われていないコードを削りやすいという特性があります。
  • パイプライン処理: `data |> fn1 |> fn2` のようなデータの流れを重視する場合。

—

4. 現場で役立つ「型」の小技

もしあなたが「オブジェクトの柔軟性」と「関数の独立性」の両方を手に入れたいなら、こんなテクニックもあります。

// メソッドではなく、Readonlyな関数型をプロパティにする
interface Processor {
readonly execute: (input: string) => string;
}

// これにより、実装の差し替えが容易になり、
// 関数としてのテストも非常に書きやすくなります。

このように定義することで、`execute`という名前空間を保ちつつ、中身は純粋な関数として振る舞わせることができます。

—

最後に:TypeScriptは「設計の道具」である

初心者の頃は「どちらが正しい書き方か」と悩みます。しかし、中級者へステップアップする鍵は、「自分の書いたコードが、将来の自分(あるいはチームメンバー)にどう影響するか」を想像することです。

  • オブジェクトが「状態」を隠蔽し、責任を負うべきなら、Interfaceのメソッドを。
  • データが「変換」され、パイプラインを通るべきなら、独立した関数を。

TypeScriptの型システムは、単なるバリデーターではありません。それは、あなたのコードの「意図」をコンパイラに伝えるための、極めて高度な言語です。

ここをマスターすれば、もう「なんとなく」でコードを書くことはなくなるはずです。さあ、次はどんな複雑な型に挑戦してみますか?応援していますよ!

タイトルとURLをコピーしました