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のエラー処理(ES2022の新機能を添えて)
Search
あけの
July 03, 2022
Programming
3.1k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TypeScriptのエラー処理(ES2022の新機能を添えて)
あけの
July 03, 2022
More Decks by あけの
See All by あけの
Reactハンズオンラーニングを読んだので感想を語る
akeno
1
720
oapi-codegenを使ってみた
akeno
0
2.9k
こんな案件は嫌だ(※個人の感想です)
akeno
1
250
SQLアンチパターンから学ぶテーブル設計
akeno
0
790
VSCode Remote Containers のすすめ
akeno
0
370
設計とテストの必要性について考える
akeno
1
320
Other Decks in Programming
See All in Programming
Androidだけじゃない、DroidKaigiで広がった私の技術スタック
akkeylab
0
100
wkhtmltopdfの次どうするか問題2026
willnet
2
1.8k
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
220
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
190
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
200
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
310
Findy - エンジニア向け会社紹介/Findy Company Deck
findyinc
6
400k
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
1
680
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
210
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
330
GemmaをJevのように使ってみる / Use Gemma like Jev
kishida
4
340
Featured
See All Featured
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
340
Building Flexible Design Systems
yeseniaperezcruz
330
41k
Balancing Empowerment & Direction
lara
6
1.3k
Become a Pro
speakerdeck
PRO
31
6.3k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
550
The SEO Collaboration Effect
kristinabergwall1
1
580
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Un-Boring Meetings
codingconduct
0
430
Paper Plane (Part 1)
katiecoart
PRO
2
11k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
850
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
240
Leo the Paperboy
mayatellez
10
2.3k
Transcript
@akeno_0810 2022.07.03 TypeScriptのエラー処理 (ES2022の新機能を添えて) Web Creator Meetup in KANSAI #2
自己紹介 About me akeno (@akeno_0810) Webエンジニア歴2年くらい Rust, API/コード設計, DevOps/開発の効率化 触っている技術
最近興味のある分野
話すこと About this talk f TypeScriptのエラー処理の紹g f エラーを返り値とする場合の型のハマりどこe f ES2022のHard
Privatb f ES2022のError Causb f 追加情報を持たせていい感じに出力する
TypeScriptのエラー処理
TypeScriptのエラー処理 エラー処理 →ある関数で処理続行不可能になった場合にどうハンドリングするか? 言語によって差がある Java→Exceptionをthrowする Rust→Result型やOption型を用いる Go→返り値でエラーを返す TypeScriptではどうするのがいいのか? try throw
new catch { HogeException(); } (HogeException e) { e.printStackTrace(); } res, err := HogeFunc() err != { fmt.Errorf(“%v”, err) } if nil fn hogeFunc() -> Result<i32, ParseIntError> { Err() } let result = hogeFunc() match result { Ok(n) => !( , n), Err(e) => !( , e), } println println "n is {}" "Error: {}"
TypeScriptのエラー処理 https://qiita.com/kabosu3d/items/680728362314f51bdcb0 XP nullやundefinedを返り値とする function : | if return return
() { (error) { ; } “success”; } hoge string null null Goo 何も考えないでいいので 呼び出し元でnullを考慮する必要があるので安全 Ba エラーが起こった以上の情報が得られない
TypeScriptのエラー処理 2. 例外をスローする GooF 詳細なエラー情報を呼び出し元に渡せる BaF 呼び出し元からはエラーが起こるかどうか読み取れなA
どのようなエラーが返ってくるかわからなA try-catchを忘れると永遠にcatchされずに落ちる function : if throw new return try catch if instanceof () { (error) { (); } “success”; } { (); } (e) { (e ){ console. (e); } } hoge hoge Error log string Error
TypeScriptのエラー処理 3. エラーを返り値とする Gooc d 詳細なエラー情報を呼び出し元に渡せB d 呼び出し元は返ってくるエラーを考慮する必要がある Bac d
エラーを返す側も呼び出し側も記述が冗長 function : | if return new return const = if instanceof () { (error) { (); } “success”; } (); (h ) { console. (e); } hoge Error hoge Error log string Error h
TypeScriptのエラー処理 4. Option/Result型を用いる Goot 呼び出し元は返ってくるエラーを考慮する必要がある Bat 言語でのサポートがなD
アプリケーション全体がライブラリに依存する
TypeScriptのエラー処理 nw nullやundefinedを返り値とすq w 例外をスローする エラーの詳細度や型安全の観点から厳しい 4. Option/Result型を用いる 特定のライブラリにアプリケーション全体が依存する状況は避けたい 個人的には殆どの場合で
3. エラーを返り値とする を使っている。
エラーを返り値とする場合の 型のハマりどころ
エラーを返り値とする場合の型のハマりどころ エラーを返り値とすることで型安全…と思いきやそうでもない エラー定義の方法によっては型の縛りが効かない場合がある class extends class extends return if instanceof
== { } { } (): HogeError { (); } ( () ) { console. (“HogeError FugaError”) } HogeError FugaError hoge FugaError hoge FugaError log Error Error function // エラーにならない functionの返り値の型はStructural Subtyping(ダックタイピング) によって判断される →お互いの実装が同じなので型を満たしていると判断される →違う型を意図していたが同じ型として扱われた instanceofは返り値のプロトタイプチェーンを見ている →実際返ってきているのはFugaErrorなのでtrue 型が壊れている状態
エラーを返り値とする場合の型のハマりどころ class extends readonly = class extends readonly = function
: return { // “HogeError”型 “HogeError”; } { // “FugaError”型 “FugaError”; } () { (); } HogeError FugaError hoge HogeError FugaError Error Error className className // エラー! 解決策 各クラスにreadonlyの文字列を持たせる →型推論によって`className`の型が絞り込まれる 関数で使用する際にその部分の型が異なる と判定されてコンパイルエラーとなる
ES2022のHard Private
ES2022のHard Private class extends readonly = class extends readonly =
{ “HogeError”; } { “PiyoError”; } HogeError PiyoError HogeError Error // “HogeError”型 // 継承している // “PiyoError”型 ... 定義できない! className className さらなる問題 継承元で定義されている型を継承先で変更できな string型で指定すると型判定ができない 困った… →継承先にプロパティを渡さなければ解決する! (ちなみにSoft PrivateではJavaScriptに変換された 際の挙動が異なるため実現できない)
ES2022のHard Private class extends readonly = class extends readonly =
{ “HogeError”; } { “PiyoError”; } HogeError PiyoError HogeError Error // “HogeError”型 // 継承している // “PiyoError”型が定義できる! #className #className Hard Privateを用いた解決 (https://ics.media/entry/220610/) Hard Private ES2022で追加されたプライベートプロパティの宣言 TypeScriptとしてはv3.8から使えた Soft Private のような宣言 この2つはトランスパイルの結果が異なる 継承を用いても型安全にエラーを処理できる! private hoge = “hoge”
ES2022のError Cause
ES2022のError Cause interface ?: interface ?: interface new ?: ?:
: ?: ?: : { ; } { ; } { ( , ) ; ( , ) ; } ErrorOptions Error Error Error ErrorConstructor ErrorOptions Error ErrorOptions Error cause cause message options message options string string ES2022のエラー周りの型定義 interface : : ?: interface new ?: : ?: : readonly : declare var : { ; ; ; } { ( ) ; ( ) ; ; } Error ; Error ErrorConstructor Error Error Error ErrorConstructor name message stack message message prototype string string string string string ちなみにES5ではこう コンストラクタにOptionsが渡せるようになっている
ES2022のError Cause つまりこういうことができる // ES2022 error cause // throw error
const = : : => const ... = if ! return ... return try throw new new catch if instanceof ( ) { { , , , } e; ( cause) { rest, name: e.name, msg: e.message}; {name: name, msg: message, cause: (cause)}; } { ( , {cause: ( )}); } (e) { (e ) { console. ( . ( (e))); } } printErr Error CustomErr printErr ResError ReqError ResError log printErr e name message cause rest JSON stringify "a" "b" エラーの入れ¥ 再帰的に取り出 いい感じに出力 深い階層で起こったエラー をWrapして、上の階層に 返すことが容易になった {"name":"Error","msg":"a","cause":{"name":"Error","msg":"b"}}
追加情報を持たせていい感じにする
追加情報を持たせていい感じにする export class extends : constructor : : : :
= { < , >; ( , { , } { ; < , > } ) { (message, { cause }); .obj obj; } } CustomError Record Error Record Error string unknown string string unknown super this obj message cause obj cause obj エラーには追加情報がつきもの ファイル名や実行された際の引数等、message: string で表現するには限界がある アプリケーション側でカスタムしたエラーを定義して、それを継承していく
追加情報を持たせていい感じにする 出力が面倒になってくるのでロギングライブラリを用いる https://github.com/pinojs/pino new new const = => ( ,
{ cause: ( ), obj: {hoge: } }); ({ formatters: { : ( , ) ({ level: label, }), }, browser: { asObject: , }, }); logger. (e); logger. ({e}); ResError ReqError pino level error error "a" "b" "huga" logger true label _ { time: 1656824412503, level: 50, obj: { hoge: "huga" } } { time: 1656824412503, level: 50, e: Error: a at file:///Users/**masked**/Projects/ts-error-demo/main.ts:37:11 Caused by Error: b at file:///Users/**masked**/Projects/ts-error-demo/main.ts:37:37 } errortraceとobjを一緒に出せたはずなのだが、 出来ない… with deno
追加情報を持たせていい感じにする { : , : , : , : ,
: { : , : , : , : { : } }, : } "level" "time" 1656825987852 "pid" 50218 "hostname" "err" "type" "message" "stack" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n "obj" "hoge" "msg" "error" "**masked**" "ResError" "a: b" "Error: a at Object.<anonymous> (/Users/**masked**/Projects/ts-error-demo-node/dist/main.js:31:11) at Module._compile (node:internal/modules/cjs/loader:1105:14) at Module._extensions..js (node:internal/modules/cjs/loader:1159:10) at Module.load (node:internal/modules/cjs/loader:981:32) at Module._load (node:internal/modules/cjs/loader:827:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12) at node:internal/main/run_main_module:17:47 caused by: Error: b at Object.<anonymous> (/Users/**masked**/Projects/ts-error-demo-node/dist/main.js:31:47) at Module._compile (node:internal/modules/cjs/loader:1105:14) at Module._extensions..js (node:internal/modules/cjs/loader:1159:10) at Module.load (node:internal/modules/cjs/loader:981:32) at Module._load (node:internal/modules/cjs/loader:827:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12) at node:internal/main/run_main_module:17:47" "huga" "a" with node.js
まとめ
Thank you! まとめ TypeScriptのエラー処理には実装の選択肢があ 型安全かつ使うハードルの低いものを選びたc TypeScriptの型は実装ベースで判断され
型を明確に異なるものにしたい場合は工夫が必0 ES2022(TS3.8)で入ったHard Privateが使え ES2022でError Causeが入っf エラーの原因を保持しやすくなった エラー処理は雑になりやすい部分なので、 安全かつ後から原因を追跡できるように実装していきたい