【入門編】Interfaceの「構造的部分型」を逆手に取ったMocking戦略 – TypeScript コア・型システムの基礎解析バイブル

こんにちは。TypeScriptの深淵へようこそ。

現場で巨大なインターフェースを前にして、「テストのためにこの全部を実装しなきゃいけないの……?」と途方に暮れたことはありませんか?実は、TypeScriptの「構造的部分型(Structural Subtyping)」という特性を理解すれば、その悩みは一瞬で解消されます。

今日は、TypeScriptがどのように型を見ているのか、その「本質」を突き、スマートなMocking戦略を伝授します。ここをマスターすれば、あなたのテストコードは劇的に美しくなりますよ。

—

1. TypeScriptの型は「名前」ではなく「形」で判断される

まず、TypeScriptの最も重要な哲学を知りましょう。JavaやC#のような「公称的部分型(Nominal Subtyping)」の言語では、たとえ中身が同じでも、型名が違えば「別物」として扱われます。

しかし、TypeScriptは違います。「このオブジェクトは、要求されたメンバをすべて持っているか?」という「形(構造)」だけを見ます。

巨大なインターフェースの例

例えば、以下のような巨大なユーザー定義があるとします。

interface UserProfile {
id: string;
name: string;
email: string;
settings: { theme: string; notifications: boolean };
lastLogin: Date;
// …あと50個くらいのプロパティ
}

このインターフェースを引数に取る関数をテストしたいとき、すべてのプロパティを埋めるのは時間の無駄ですよね。

—

2. 構造的部分型を逆手に取った「部分Mock」戦略

TypeScriptは、「型が要求する最小限のメンバさえあれば、それはその型として認められる」という寛容さを持っています。これを利用して、テストに必要な部分だけを抽出した「Mock」を作ります。

実践:必要な部分だけを実装する

// テスト対象の関数
function getDisplayName(user: UserProfile): string {
return `User: ${user.name}`;
}

// テスト用コード
// 本来はUserProfile型が必要だが、nameさえあればTypeScriptは文句を言わない
const mockUser = {
name: “Taro Yamada”
} as UserProfile;

// これでエラーなく実行できます
console.log(getDisplayName(mockUser)); // “User: Taro Yamada”

なぜこれでうまくいくのか?

`as UserProfile` (型アサーション)を使うことで、「コンパイラさん、これはUserProfileの形をしてるから信じて!」と伝えています。実際に関数内で `user.name` を呼ぶ分には問題なく動きます。

ただし、「本当に存在するプロパティか」はコンパイラがチェックしてくれます。もし `user.nmae` のようにタイポすれば、TypeScriptは即座にエラーを吐きます。これがTypeScriptの強みです。

—

3. 陥りやすい「文法エラー」と罠

初学者がよくやるミスは、「あえて全部実装しようとして泥沼にはまる」ことです。また、以下のようなケースには注意が必要です。

罠:`undefined` へのアクセス

もし関数内で `user.settings.theme` にアクセスしている場合、上の例のように `name` だけをMockにすると、実行時に「Cannot read property ‘theme’ of undefined」でクラッシュします。

解決策:Utility Typesの活用
全てを実装したくないが、一部の深い階層までMockしたい場合は、`Partial` を使いましょう。

// すべてのプロパティを「あってもなくても良い(undefined許容)」状態にする
const partialMock: Partial = {
name: “Taro”,
settings: { theme: “dark”, notifications: true }
};

—

4. プロの現場での「型変換」の極意

さらに進んだテクニックとして、「テスト用の型を定義する」という方法をおすすめします。

// 必要な部分だけを抜き出した型を事前に作っておく
type UserMock = Pick;

const myMock: UserMock = {
id: ‘1’,
name: ‘Taro’
};

// 最後に型をキャストして関数に渡す
getDisplayName(myMock as UserProfile);

こうすることで、テストコードの可読性が保たれ、型安全性を維持しながらMockingが可能です。

—

先輩からのメッセージ

TypeScriptを学ぶ上で最も大切なことは、「コンパイラを敵ではなく、最も優秀なペアプログラミング相手にする」ことです。

構造的部分型を理解するということは、「TypeScriptがコードをどう見ているか」という視点を持つことです。最初は `as` (型アサーション)に頼りすぎることがあるかもしれませんが、それは悪いことではありません。そこから徐々に、`Pick` や `Partial` といったUtility Typesを使いこなし、より厳密で美しい型設計を目指してみてください。

ここをクリアすれば、あなたはもうTypeScriptの基礎を卒業し、一段上のアーキテクチャ設計へと進む準備ができています。また現場でお会いしましょう!

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