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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
hiroto_0411
June 25, 2025
Programming
89
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
310
大好きな「学び合い文化 」への貢献がしたい!
hyamazaki
0
16
Other Decks in Programming
See All in Programming
関東Kaggler会_NVIDIA_Nemotron_コンペ_振り返り
rick_ds
0
780
tsc.rip を支える技術 / Kyoto.なんか #8
susisu
0
4.1k
ソフトウェアラスタライザ
fadis
1
760
AIの中の人になってみる
htkym
0
150
不幸な GC
chencmd
0
850
自動化したのに回らない テスト運用の壁―AI時代の品質責任と生産性
mfunaki
0
570
承認済みなのに差戻しできてしまうバグ、型で潰せます
shinchit
0
130
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
360
My Marp Sample
sinoue0108
0
140
Press start. Python's next generation.
willingc
PRO
3
300
自分的「カンファレンスの楽しみ方」
syumai
0
160
AI時代に学ぶ 好きなルール 嫌いなルール Linter編
shorty5121
0
720
Featured
See All Featured
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
300
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.4k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
エンジニアに許された特別な時間の終わり
watany
108
250k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.5k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Designing for Performance
lara
611
70k
Docker and Python
trallard
47
4.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.8k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
220
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の問題など)を早期発見できる 型必須のルール設定 → チーム全体で一貫した、より安全で効果的な単体テストを 実装できる