Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
TypeScript+ESLintで守る単体テストの品質
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
hiroto_0411
June 25, 2025
Programming
98
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
17
Other Decks in Programming
See All in Programming
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
480
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
460
カツオ、ご期待ください
suneo3476
0
150
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
340
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
Heart of Swift Concurrency
koher
0
1.2k
GitHubハンズオン講座 — 実務レベルのチーム開発のフローを身につけよう
junhat6
0
120
APNsからLive Activityを開始する話
yumnumm
0
150
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
490
ジョジョの世界をXRで再現する
mofurune
0
140
Findy - エンジニア向け会社紹介/Findy Company Deck
findyinc
6
400k
mrbgem 三角測量 開発
ogom
0
210
Featured
See All Featured
Why Our Code Smells
bkeepers
PRO
340
58k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.2k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
310
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
Prompt Engineering for Job Search
mfonobong
0
490
Docker and Python
trallard
47
4.2k
Producing Creativity
orderedlist
PRO
348
41k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
620
Exploring anti-patterns in Rails
aemeredith
4
520
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
How to Think Like a Performance Engineer
csswizardry
28
2.9k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
460
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の問題など)を早期発見できる 型必須のルール設定 → チーム全体で一貫した、より安全で効果的な単体テストを 実装できる