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
例外はスローするなリターンし ろ
Search
Nakano as a Service
October 30, 2024
Programming
92
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
例外はスローするなリターンし ろ
Nakano as a Service
October 30, 2024
More Decks by Nakano as a Service
See All by Nakano as a Service
StripeとNotion、AIで作る決済自動化の裏側
nakanoasaservice
0
26
TypeScript type challengesを解いてみよう
nakanoasaservice
0
160
Hasuraにコントリビュートした話
nakanoasaservice
0
75
Other Decks in Programming
See All in Programming
運用ダッシュボードの設計を誰も教えてくれないのだけどみなさんどうしてるんですか? - チームに監視するという文化を根付かせるための第一歩を踏みたい -
satoshi256kbyte
1
120
Go 1.27 における memory allocation の高速化
andpad
0
180
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
140
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
490
自動化したのに回らない テスト運用の壁―AI時代の品質責任と生産性
mfunaki
0
170
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
220
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
480
仕様駆動開発へのトライを機に チームに適合する手法を模索し続けている話
freee
PRO
0
500
torikago - Ruby::Boxで照らすモジュラモノリスの実行境界
se4weed
1
370
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
790
AIを紡ぐPMのお話
swdtkuy
0
100
Featured
See All Featured
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Building Applications with DynamoDB
mza
96
7.2k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
280
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
470
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
The Curious Case for Waylosing
cassininazir
1
450
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
119
120k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.7k
Between Models and Reality
mayunak
4
390
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
Optimizing for Happiness
mojombo
378
71k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
460
Transcript
例外はスローするなリターンし ろ
皆さん例外処理ちゃんとやってますか? 例: トークンの中身をパースして返す ついつい例外処理をサボりがち そんなあなたに function verifyToken(token: string): UserSessionInfo {
if (!isTokenValid(token)) { throw new Error("token is not valid") } return parseToken(token) } const session = verifyToken(cookie().token) /* 不正なトークンが渡ってきた場合が考慮できてない! */ const user = getUser(session.userId) // ここまでたどり着かない
例外はリターンしましょう
メリット1: 例外処理をしないと値を使えなくなる Error でないことを確かめないと userId に使えない! function verifyToken(token: string): UserSessionInfo
| Error { if (!isTokenValid(token)) { // 例外をリターンするようにした return new Error("token is not valid") } return parseToken(token) }
メリット1: 例外処理をしないと値を使えなくなる エラー処理をちゃんとすれば値を使える! function verifyToken(token: string): UserSessionInfo | Error {
if (!isTokenValid(token)) { // 例外をリターンするようにした return new Error("token is not valid") } return parseToken(token) } const session = verifyToken(cookie().token) if (session instanceof Error) { // エラーを処理する redirect("/login") return } // userId が使える! const user = getUser(session.userId)
メリット2: どんなエラーが起こるのかわかる 独自の例外クラスを定義しておけば、関数の返り値の型を見るだけでどんなエラーが起こるのかわかる 皆さんもエラーをリターンしてみてください! // 独自の例外クラスを定義 class InvalidTokenError extends Error
{} class InvalidPayloadError extends Error {} // 関数の返り値の型を見ればどんなエラーが起こるかわかる function verifyToken(token: string): UserSessionInfo | InvalidTokenError | InvalidPayloadError { if (!isTokenValid(token)) { return new InvalidTokenError() } // トークンのパースでもエラーが発生する場合 const payload = parseToken(token) if (payload instanceof Error) { return new InvalidPayloadError() } }
え、独自の例外クラスをいちいち定義するのがめんど くさい?
判別可能なエラー型で例外クラスの定義をサボる 独自の例外クラスを定義せずとも code で区別できるエラーを定義できる 以下のように使う function verifyToken(token: string): UserSessionInfo |
PubErr<"INVALID_TOKEN", string> | PubErr<"INVALID_PAYLOAD"> { if (!isTokenValid(token)) { return new PubErr({ code: "INVALID_TOKEN", cause: token }) } const payload = parseToken(token) if (payload instanceof Error) { return new PubErr({code: "INVALID_PAYLOAD" }) } return payload } const session = verifyToken(cookie().token) if (session instanceof PubErr) { if (session.code === "INVALID_TOKEN") { // PubErr<"INVALID_TOKEN"> 型として扱われる const token = session.cause // cause に原因となったtoken (string )が入っている }
判別可能なエラー型って何? 近々記事を書く予定なので詳しいことは中野に聞いてください。 とりあえず code でエラーが区別できるようになるやつと覚えていただけるとありがたいです。 定義は以下 interface PubErrProps<C extends string,
E = never> { code: C; message: string; cause?: E; } export class PubErr<C extends string, E = never> extends Error { code: C; cause!: E; constructor({ code, message, cause }: PubErrProps<C, E>) { super(message, { cause }); this.code = code; } }
え、呼び出し側でいちいち例外処理するのがだるい? function verifyToken(token: string): UserSessionInfo | PubErr<"INVALID_TOKEN", string> | PubErr<"UNEXPECTED_PAYLOAD">
{ // isValidToken がエラーをリターンするvalidateToken に変わった const validToken = verifyToken(token) if (validToken instanceof Error) { return new PubErr({ code: "INVALID_TOKEN", cause: token }) } const payload = parseToken(validToken) if (payload instanceof Error) { return new PubErr({code: "UNEXPECTED_PAYLOAD" }) } return payload }
Neverthrow のsafeTry を使う if 文が不要になった(代わりに見たこともないような構文が増えた) 。かなり端折った説明なので雰囲気だけ捉 えてほしい。 他にも便利な機能があるのでNeverthrow の公式ドキュメントを見てみてください Neverthrow
公式ドキュメント Neverthrow は新しい概念がそこそこあるのでチームでやるときはオンボーディングを丁寧にしてください。 function verifyToken(token: string) { return safeTry(function*() { const validToken = yield* verifyToken(token) // if 文は不要! const payload = yield* parseToken(validToken) // if 文は不要! return ok(payload) }) }
まとめ 例外をリターンすることで以下のメリットがある 呼び出し元に例外処理を強制できる どんなエラーが起こるのか型を見ればわかる 最初からすべてを実践する必要はない 1. Error をリターンする 2. 独自例外クラスを定義する
3. 判別可能なエラー型で独自例外クラスの定義をサボる 4. Neverthrow で呼び出し元の例外処理を端折る 補足: 返り値の型は推論されるので書かなくていい みんなも例外をリターンしてみてね!