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のエラー処理(ES2022の新機能を添えて)
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
あけの
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
710
oapi-codegenを使ってみた
akeno
0
2.9k
こんな案件は嫌だ(※個人の感想です)
akeno
1
240
SQLアンチパターンから学ぶテーブル設計
akeno
0
780
VSCode Remote Containers のすすめ
akeno
0
360
設計とテストの必要性について考える
akeno
1
320
Other Decks in Programming
See All in Programming
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
700
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
180
【デモ】Kiroで体験する仕様駆動開発|設計からコーディングまでAIと進める開発フロー
cmkudo
0
520
「つくるAI」だけではバグは見つからない ~テストに必要な「見つけるAI」を分離させる戦略~
mfunaki
0
210
言葉の格闘技のススメ~紙とペンと言葉から始める、キャリアの描き方~
progresscicada
2
190
【QA Test Talk Vol.8】AI-DLC による Whole Team Approach の加速
pkshadeck
PRO
0
260
T3DD26: From RAGs to Riches
martinhelmich
0
120
初めての模倣学習とVLA
natsutan
0
340
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
250
PyConJP2026_wat_Python × Signal Processing: How to Draw Pictures with Sound Using Spectrogram Art
wat
0
590
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
5
1.8k
楽しそうなつよつよエンジニアと目が死んでる僕/A brilliant engineer having a blast, and dead-eyed me.
3l4l5
2
260
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
760
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
310
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.5k
Into the Great Unknown - MozCon
thekraken
41
2.7k
The Spectacular Lies of Maps
axbom
PRO
1
950
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
45k
Accessibility Awareness
sabderemane
1
190
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Designing for Timeless Needs
cassininazir
1
460
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
540
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 エラーの原因を保持しやすくなった エラー処理は雑になりやすい部分なので、 安全かつ後から原因を追跡できるように実装していきたい