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
えっ!!コードを読まずに開発を!?
hananouchi
0
230
共通化で考えるべきは、実装より公開する型だった
codeegg
0
270
関数型プログラミングのメリットって何だろう?
wanko_it
0
190
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.7k
Haskell/Servantを通してWebミドルウェアを捉え直す
pizzacat83
1
610
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
180
AI がコードを書く時代における新卒エンジニアの仕事風景 (2026) / New Graduate Engineers in the Era of AI Coding (2026)
sushichan044
0
230
Apache Hive: そしてCloud Native Lakehouseへ
okumin
1
170
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
270
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
180
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
1
210
SLOをサービス品質の共通言語にするために 取り組んできたこと
wakana0222
0
540
Featured
See All Featured
Building Adaptive Systems
keathley
44
3.1k
What does AI have to do with Human Rights?
axbom
PRO
1
2.3k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
900
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
440
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
280
For a Future-Friendly Web
brad_frost
183
10k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Discover your Explorer Soul
emna__ayadi
2
1.2k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
200
Typedesign – Prime Four
hannesfritz
42
3.1k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
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の問題など)を早期発見できる 型必須のルール設定 → チーム全体で一貫した、より安全で効果的な単体テストを 実装できる