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の「Result型」のすゝめ
Search
Kodak
February 05, 2023
Technology
5.6k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TypeScriptの「Result型」のすゝめ
Kodak
February 05, 2023
Other Decks in Technology
See All in Technology
Devin プロモコードの受け取りと適用(2026.10.27)
kinopeee
1
620
アカウント統制の健康診断
kenichinakamura
1
210
Flutter Widget Previewerで始めるUIプレビューとVRTの自動化
sakusaku3939
0
110
LLM-as-a-Judgeは本当に信頼できるのか――評価器を評価する話
taka_aki
3
1.1k
Adversary Infrastructure Hunting101
disconinja
0
160
AIに任せられるFlutterコードベースを作る 〜仕様をコードで表し、ハーネスで守る〜
myohei
1
290
Codex を使った障害対応机上演習の実際
orgachem
PRO
0
370
データマネジメント × 法務で作りあげる、 freeeの新しいデータガバナンスへの軌跡
freee
PRO
2
480
Agent 活用環境の構築・運用のための AWS サービスのご紹介/agentcore-for-building-and-operating-agents
ren8k
1
200
Deep Data Security 機能解説
oracle4engineer
PRO
3
950
Autonomous AI Lakehouse - Live AI Hubから始めるセキュアなAIデータ活用 -
oracle4engineer
PRO
2
160
AIエージェントに 権限と鍵をどこまで渡すか
nrinetcom
PRO
2
120
Featured
See All Featured
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
500
Code Review Best Practice
trishagee
74
20k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.9k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.7k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
Large-scale JavaScript Application Architecture
addyosmani
516
110k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
490
Un-Boring Meetings
codingconduct
0
470
Docker and Python
trallard
47
4.2k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
50
10k
Transcript
「Result型」のすゝめ 第20回「技術共有会」
今回お話する内容 リンク https://qiita.com/Kodak_tmo/items/ d48eb3497be18896b999
「Result型」とは? 何かしら処理の成功、または失敗を表す型のこと。 Swift、Scala、最近流行りのRust等には言語自体に「Result型」を定義できる仕組みがある。 残念ながら、TypeScriptには、そのような仕組みが無いため、自分で実装する必要がある。 Result型いいなぁ.... Result型あるー Result型あるー Result型あるー ....
「Result型」を見てみよう type Result<T, E extends Error> = Success<T> | Failure<E>;
class Success<T> { readonly value: T; constructor(value: T) { this.value = value; } isSuccess(): this is Success<T> { return true; } isFailure(): this is Failure<Error> { return false; } } class Failure<E extends Error> { readonly error: E; constructor(error: E) { this.error = error; } isSuccess(): this is Success<unknown> { return false; } isFailure(): this is Failure<E> { return true; } }
「Result型」を見てみよう type Result<T, E extends Error> = Success<T> | Failure<E>;
class Success<T> { readonly value: T; constructor(value: T) { this.value = value; } isSuccess(): this is Success<T> { return true; } isFailure(): this is Failure<Error> { return false; } } class Failure<E extends Error> { readonly error: E; constructor(error: E) { this.error = error; } isSuccess(): this is Success<unknown> { return false; } isFailure(): this is Failure<E> { return true; } } 成功クラス 失敗クラス
「Result型」を見てみよう type Result<T, E extends Error> = Success<T> | Failure<E>;
class Success<T> { readonly value: T; constructor(value: T) { this.value = value; } isSuccess(): this is Success<T> { return true; } isFailure(): this is Failure<Error> { return false; } } class Failure<E extends Error> { readonly error: E; constructor(error: E) { this.error = error; } isSuccess(): this is Success<unknown> { return false; } isFailure(): this is Failure<E> { return true; } } コンストラクターで成功の 結果を受け取る。 インスタンス変数から結果 を参照できるようにする。 コンストラクターで失敗の 結果を受け取る。 インスタンス変数から結果 を参照できるようにする。
「Result型」を見てみよう type Result<T, E extends Error> = Success<T> | Failure<E>;
class Success<T> { readonly value: T; constructor(value: T) { this.value = value; } isSuccess(): this is Success<T> { return true; } isFailure(): this is Failure<Error> { return false; } } class Failure<E extends Error> { readonly error: E; constructor(error: E) { this.error = error; } isSuccess(): this is Success<unknown> { return false; } isFailure(): this is Failure<E> { return true; } } 成功 or 失敗の判定メソッ ドを用意する。 成功 or 失敗の判定メソッ ドを用意する。
「Result型」を見てみよう type Result<T, E extends Error> = Success<T> | Failure<E>;
class Success<T> { readonly value: T; constructor(value: T) { this.value = value; } isSuccess(): this is Success<T> { return true; } isFailure(): this is Failure<Error> { return false; } } class Failure<E extends Error> { readonly error: E; constructor(error: E) { this.error = error; } isSuccess(): this is Success<unknown> { return false; } isFailure(): this is Failure<E> { return true; } } ※実は、各クラスの反対のメソッド(成功なら失 敗を判定するメソッド)は使用していない。 しかし、このメソッドを実装しておかないと、 コード補完が上手く働かない。 ※実は、各クラスの反対のメソッド(成功なら失敗を判定 するメソッド)は使用していない。 しかし、このメソッドを実装しておかないと、コード補完が 上手く働かない。 仕組みは以下と同じ。TypeScriptは「構造的部分型」を 採用しているのでこのような結果になる。
「Result型」を見てみよう type Result<T, E extends Error> = Success<T> | Failure<E>;
class Success<T> { readonly value: T; constructor(value: T) { this.value = value; } isSuccess(): this is Success<T> { return true; } isFailure(): this is Failure<Error> { return false; } } class Failure<E extends Error> { readonly error: E; constructor(error: E) { this.error = error; } isSuccess(): this is Success<unknown> { return false; } isFailure(): this is Failure<E> { return true; } } 最後に、Result型を定義する。 Success型とFailure型をUnion型にする。 何かしら処理の成功、または失敗を表す型と なる。
「Result型」の使い方(その1)
「Result型」の使い方(その2)
「Result型」の特徴・まとめ - 「Result型」は、エラーハンドリング手法の1つ。 - try-catchを(可能な限り)用いないので、以下の恩恵が得られる。 - エラーハンドリングが容易。 - 型安全。 -
エラーのテストが容易。
エラーハンドリングが容易とは?(その1) // こんなことになったことはない? ライブラリ、 API、JSON parse するたびに try-catch して、エラーハンドリングが複雑化。。。 type
JsonType = { msg: string } function fooChildren <T>(str: string) { try { return JSON.parse(str) as T } catch(error) { // ...省略 } } function foo<T>(str: string) { try { const json1 = fooChildren <T>(str) const json2 = fooChildren <T>(str) return { json1, json2 } } catch(error) { // ...省略(json1でエラーが出た場合、 json2でエラーが出た場合でエラーの出し分け、どうコントロールするかを考える必要がある) } } function main() { try { return foo<JsonType >('{ "msg":"hello" }' ) // {“json1”:{“msg”:”hello”}, “json2”:{“msg”:”hello”}} } catch(error) { // ...省略(json1でエラーが出た場合、 json2でエラーが出た場合でエラーの出し分け、どうコントロールするかを考える必要がある) } } ・エラーハンドリング箇所が多い ・考えることが多い ・コードが読み辛い
エラーハンドリングが容易とは?(その2) // こんなことになったことはない? ライブラリ、 API、JSON parse するたびにtry-catchして、エラーハンドリングが複雑化。。。 type JsonType= {
msg: string } function fooChildren <T>(str: string) { try { return JSON.parse(str) as T } catch(error) { // ...省略 } } function foo<T>(str: string) { const json1 = fooChildren <T>(str) const json2 = fooChildren <T>(str) return { json1, json2 } } function main() { try { return foo<JsonType>('{ "msg":"hello" }' ) // {“json1”:{“msg”:”hello”}, “json2”:{“msg”:”hello”}} } catch(error) { if (error instanceof Error) { // エラー判別処理が巨大化・複雑化 if (error.name === 'xxxx') { // ...省略 } if (error.name === 'xxxx') { // ...省略 } } throw new Error('unknown Error' ) } } ・エラー判定処理が巨大化・複雑化
「Result型」を使うと?
エラーハンドリングが容易とは?(Result型) type JsonType= { msg: string } function fooChildren <T>(str:
string): Result<T, Error> { try { const json = JSON.parse(str) as T return new Success(json) } catch(error) { // ...省略 return new Failure(new Error('unknown Error' )) } } function foo<T>(str: string): Result<{json1: T,json2: T }, Error> { const result1 = fooChildren <T>(str) if (result1.isFailure()) { // joson1のエラー return new Failure(result1.error) } const result2 = fooChildren <T>(str) if (result2.isFailure()) { // joson2のエラー return new Failure(result2.error) } return new Success({json1:result1.value, json2: result2.value}) } function main() { const result = foo<JsonType>('{ "msg":"hello" }' ) // {“json1”:{“msg”:”hello”}, “json2”:{“msg”:”hello”}} if(result.isFailure()) { // ...省略(そのまま出力で OK。ここでごちゃごちゃしない) return } return result.value } ・エラー判定処理がif文の下にすぐ書ける ・1つ1つのエラーを個別に考えることができる ・コードが見易い
型安全とは? type JsonType = { msg: string } function fooChildren
<T>(str: string) { try { return JSON.parse(str) as T } catch(error) { // ...省略 } } function foo<T>(str: string) { // foo() の戻り値の型も {json1:T, json2:T} となり、catchが考慮されない。。。 try { const json1 = fooChildren <T>(str) // json1 の型、fooChildren() の戻り値の型は T。つまり、 catchされたエラーが考慮されていない。。。 const json2 = fooChildren <T>(str) // json2 の型、fooChildren() の戻り値の型は T。つまり、 catchされたエラーが考慮されていない。。。 return { json1, json2 } } catch(error) { // ...省略 } } function main() { try { return foo<JsonType >('{ "msg":"hello" }' ) // {“json1”:{“msg”:”hello”}, “json2”:{“msg”:”hello”}} } catch(error) { // ...省略 } } ・catchされたエラーが型として表現されない。呼び出した関数 がエラーになるかどうかは、実際にコードを見なくてはならな い。「Result型」を使えば、このあたりは考慮しなくて良い。
エラーのテストが容易とは? テストにおいて、エラー用のマッチャー( toThrow()、toThrowError())を使用しなくてよくなり、 toBe() や toEqual() を使用 して評価することができる。 const result
= main() expect(result.isFailure () ? result.error.statusCode : undefined ).toBe(500) expect(result.isFailure () ? result.error.code : undefined ).toBe('APP_FOO_FUNCTION_ERROR' )
「Qiita」で頂いたコメントを見る
Qiitaでのコメント(その1) Go言語は、各プログラミング言語が抱える問題の 1つである言語自体の複雑化。それによる批判などを解決した上で、 各言語の良い部分を参考にして作られた比較的新しい言語です。 そうやって産まれた言語で、 try-catchが無い。。。というのは、考えさせられるものがありますね。 (ちなみにGo言語のエラーハンドリングは、以下のように `if` で行います。Result型に似てますよね? 2009年生まれだよ
Qiitaでのコメント(その2) 上のリンク先から例外箇所について私なりに纏め てみると、「例外は実質的に見えない goto文であり、目に見える goto文よりもわかり辛い。例外があること で、そのコードが正しい かどうかを判断するには、 どこか別なところ を見なければならず、 多くのことを頭の中で一時的に記憶しておく必要があり、大変であ
る。」という感じです。 例外は実質的に見えない goto文なんだよ。ということが全てを物語っている気がしますね。
「Result型」の特徴・まとめ(再) - 「Result型」は、エラーハンドリング手法の1つ。 - try-catchを(可能な限り)用いないので、以下の恩恵が得られる。 - エラーハンドリングが容易。 - 型安全。 -
エラーのテストが容易。 是非、使ってみてください!!!!