🙈

TypeScriptでnullガードした上でnullを受け付けない関数をコールしても型エラーが出る時の対処法

2022/09/24に公開

前提条件

  • アプリケーションの様々なページで利用される、商品の金額を共通のフォーマットに変換する関数を使いたい
  • 例外的に今回の使用箇所でのみ、共通関数に渡す引数のオブジェクトの中のプロパティが null の場合がある

お困りポイント

値をフォーマットする共通関数では、nullの可能性はない前提で引数の型が定義されている。
そこで、nullガードを入れてからその関数を呼び出すようにしてみたが、TypeScriptで型エラーが出てしまう。
@ts-ignore などの強引にTypeScriptを黙らせる以外の方法でエラーメッセージを出ないようにしたい...

共通処理:formatPriceText.ts

📝 引数の配列の中のオブジェクトは必ずnumber型で存在する

export const formatPriceText = (
  variations: { price: number }[];
): string => {
  // 中略: オブジェクトの中の整数値を 「¥1000 ~ ¥2000」 の文字列に変換する処理
};

呼び出し側:Item.vue

🔥 この画面だけ、price の値がnullのパターンが存在する
🔥 「number | null型」の値を「number型」が引数の関数には渡せない旨のエラーメッセージが出てしまう

const itemPriceText = computed(() => {
  // price は、ここの場所では number | null 型
  const variations = item.variations
    .map((variation) => {
      return {
        price: variation.price,
      };
    })
    .filter((variation) => variation.price !== null);
  
  // ここで 「number | null型」の値を「number型」が引数の関数には渡せない旨のエラーメッセージが出てしまう
  return formatPriceText({ variations });
});

対処法

📝 is を使って明示的に型の絞り込み結果をTypeScriptに伝える!
(hoge: hoge is { hoge: string } のフォーマット)

const itemPriceText = computed(() => {
  // price は、ここの場所では number | null 型
  const variations = item.variations
    .map((variation) => {
      return {
        price: variation.price,
      };
    })
    .filter(
++    (variation): variation is { price: number } =>
       variation.price !== null
    );
  
  return formatPriceText({ variations });
});

Discussion