こんにちは。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の基礎を卒業し、一段上のアーキテクチャ設計へと進む準備ができています。また現場でお会いしましょう!