Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
TypeScript+ESLintで守る単体テストの品質
Search
hiroto_0411
June 25, 2025
Programming
88
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TypeScript+ESLintで守る単体テストの品質
Mita.ts #6での登壇資料です。
https://mitats.connpass.com/event/353424/
hiroto_0411
June 25, 2025
More Decks by hiroto_0411
See All by hiroto_0411
DynamoDBは怖くない!〜テーブル設計の勘所とテスト戦略〜
hyamazaki
1
300
大好きな「学び合い文化 」への貢献がしたい!
hyamazaki
0
16
Other Decks in Programming
See All in Programming
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
330
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
190
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
190
freee が目指す データ マネジメント戦略 AI-Ready 時代を支える 攻めのガバナンスとは
freee
PRO
0
370
仕様駆動開発へのトライを機に チームに適合する手法を模索し続けている話
freee
PRO
0
510
琵琶湖の水は止められてもNet--HTTPのリトライは止められない / You might be able to stop the water flow of Lake Biwa but you can't stop Net::HTTP retries
luccafort
PRO
0
720
Claude Code全社展開のためにやったことn選~プラグイン302個・コミッター271人を支えるために~
kenchan
5
1.5k
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
1.8k
ITヒヤリハットを整理してみた ~ライフサイクルと原因から考える再発防止策~
koukimiura
1
140
今さら聞けない .NET CLI
htkym
0
190
属人化した知識を、 AIが辿れる地図にする
pkshadeck
PRO
1
170
FDEが実現するAI駆動経営の現在地
gonta
2
280
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.8k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
350
Rails Girls Zürich Keynote
gr2m
96
14k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.5k
Test your architecture with Archunit
thirion
1
2.3k
Automating Front-end Workflow
addyosmani
1369
210k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
940
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.9k
Typedesign – Prime Four
hannesfritz
42
3.1k
BBQ
matthewcrist
89
10k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.8k
The Pragmatic Product Professional
lauravandoore
37
7.4k
Transcript
TypeScript+ESLintで守る単体テストの品質 TypeScript+ESLintで守る単体テストの品質 ~型を明示しないテストが招いた落とし穴とその改善策~ 株式会社Schoo 山﨑 光都 Mita.ts #6 2025/06/25
自己紹介 株式会社Schoo 山﨑 光都 (やまざき ひろと) @hiroto_0411(X, Qiita) 業務内容 レガシーシステムのリプレイス
による「次世代プラットフォー ムの構築」 Golang/TypeScript TypeScript歴は1ヶ月ほど です 技術発信文化の醸成
今日話すこと TypeScript単体テストで型を明示的に指定する重要性 型を明示しないテストの問題点 ESLintによる解決策 ※単体テストはVitestを使っています
プロジェクト構成 BE (Go,モジュラーモノリス) ←→ BFF (TypeScript + Hono) ←→ FE(Nuxt)
BFFの役割 BEのAPIをFEが扱いやすい形に整形 gRPC通信処理 gRPC <-> TypeScriptのデータ変換 &整形 認証・認可ロジック BFFを採用した理由 BEはモジュラーモノリスアーキテク チャを採用ドメインごとのシンプル なAPIのみを提供しているためコン テキストがまたがる場合がある BFFがつなぎ役を担い、FEが扱いや すい形に整える
Domain/RepositoryとServiceの実装 // User型の定義 export type User = { userId: string;
name: string; }; // Domain/Repository層のインターフェース export interface IUserRepository { getUser( context: Context): Promise< User>; } // Service層の実装 export const userService = { async getUserByJWT( repository: IUserRepository, context: Context ): Promise< User> { // ユーザー情報をdomain/repositoryのinterfaceを呼び出して取得する const userResponse = await repository. getUser(context); return { ...userResponse, }; }, };
型を明示的に指定しない単体テストの問題点 // User型にorganizationが追加された export type User = { userId: string;
name: string; organization: { // ← 新しく追加 id: string; name: string; }; }; 仕様が変わりinterfaceの返り値が変わった
型を明示的に指定しない単体テストの問題点 // 問題のあるテストコード test( "repositoryからデータを取得できたとき、その値を返すこと", async () => { const
mockUser = { // 型指定なし userId: "user1", name: "テストユーザー" }; const mockRepository: IUserRepository = { getUser: vi. fn(). mockResolvedValue(mockUser), }; // テスト実行 const result: User = await userService. getUser(mockRepository, mockContext); // 検証 expect(result). toEqual({ ...mockUser, }); }); 問題点: interfaceが変更されてもテストでエラーにならない
型を明示的に指定しない単体テストの問題点 // vitestのmockResolvedValueの実装 mockResolvedValue( value: Awaited< ReturnType<T>>): this; interface MockInstance<T
extends Procedure = Procedure> 問題点: mockResolvedValue(value: Awaited<ReturnType<T>>): this で使う値 (mockUser)に明確な型定義がないため、戻り値型がanyとして解釈されてしま い、interfaceが変更された場合でも型エラーとなってくれない
解決策: テストコードの変数宣言時に型必須にするESLintを設定 // eslint.config.js { files: [ "**/*.test.ts", "**/*.spec.ts"], rules:
{ "@typescript-eslint/no-explicit-any": "error", //any型の使用を禁止 "@typescript-eslint/typedef": [ "error", { "variableDeclaration": true, } ], //変数宣言時に型注釈を必須 }, }
改善後のテストコード // 改善されたテストコード test( "repositoryからデータを取得できたとき、ユーザ情報と組織情報を返すこと", async () => { const
mockUser: User = { // 明示的な型指定 userId: "user1", name: "テストユーザー", organization: { id: 'org456', name: 'Schoo', }, }; const mockRepository: IUserRepository = { getUser: vi. fn(). mockResolvedValue(mockUser), }; // テスト実行 const result: User = await userService. getUser(mockRepository, mockContext); // 検証 expect(result). toEqual({ ...mockUser, }); }); interface変更時にテストでエラーが発生し、修正漏れを防げる
まとめ 単体テストでは変数宣言時に型を明示的に指定する → interface変更時の問題 (mockの問題など)を早期発見できる 型必須のルール設定 → チーム全体で一貫した、より安全で効果的な単体テストを 実装できる