sunabox

type predicateでFirebaseのエラーハンドリングをする

前回type predicate使う場面が出てきてテンション上がって記事を書いた

type predicateで配列のundefinedを取り除いた型を付ける | sunabox配列の中にundefinedが含まれる場合、そのままfilterしても型情報からはundefinedが取り除かれない。これをtype predicateを使ってundefinedを取り除いた型を付ける方法を記載。
faviconsuna.dev

その直後にもう一つtype predicate使う場面が出てきたのでメモ

TSのバージョンを4.4に上げた時にエラーになる部分が出てきたのでそれに対応するために使用した

背景

TSを4.4にアップデートしたらエラー吐くようになった
内容見たらcatchの中のerrorオブジェクトが今までanyに推論されてたのがstrict: trueだとunknownに推論されるようになったらしい。

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html#using-unknown-in-catch-variables

エラーハンドリングでerror.messageとかやってたのがerrorがunknownになったことで怒られるようになった

try {
  ...
} catch (error) {
  console.error(error.message) // エラー
  ...
}

narrowingによる対応

解決策としては下記のようにnarrowingしてやればok
errorはErrorオブジェクトであることを教えてあげればmessageプロパティが使える形になる

try {
  ...
} catch (error) {
  if (error instanceof Error) console.error(error.message)
  ...
}

基本これでokなんだけど、一箇所firebaseのエラーハンドリングの部分だけ困った

try {
  ...
} catch (error) {
    if (error.code === 'auth/account-exists-with-different-credential') {
      // エラーハンドリング
    }
}

元々これはfirebaseのドキュメントにも書いてある書き方なんだけど、Errorオブジェクトにはcodeプロパティがないので、他の部分と同じようにinstanceof Errorとするだけじゃだめだった

type predicateを使う

narrowingでerrorオブジェクトがcodeというプロパティを持つことを示したい
そんな時に使えるのがぼくらのtype predicate

以下のようにすると行けた

type FirebaseError = {
  code: string
  message: string
  name: string
}
 
const isFirebaseError = (e: Error): e is FirebaseError => {
  return 'code' in e && 'message' in e
}
 
try {
  ...
} catch (error) {
    if (
      error instanceof Error &&
      isFirebaseError(error) &&
      error.code === 'auth/account-exists-with-different-credential'
    ) {
      // エラーハンドリング
    }
}

Firebaseから型がexportされてるか分からなかったので、codeを持つ型を自分で定義してtype predicateしてやればerrorがFirebaseErrorに推論されるのでerror.codeが通るようになった

type predicateの使い方完全に理解した!!

まとめ

TSおもしれー!!!(2回目)

参考

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html#using-unknown-in-catch-variables
Buy Me A Coffeeのbutton

目次