🔥

型ガードとundefinedのTypeErrorについて

2021/12/04に公開

型ガードについてニワカであることが発覚したので復習がてら記事にしてみました。サンプルコードでundefinedの可能性のあるものをエディターで怒って欲しかったので、ついでにTS 4.1 を導入して、noUncheckedIndexedAccessのオプションを追加したりなどしてみました。


型ガードとundefinedのTypeError

型ガードとは?

例えば、number or null といったような複数の型を持つ変数を扱うとします。そうするとnumberの時とnullの時で、2通りの選択肢が生まれますよね。しかし、numberの場合のみのロジックを記述したいといったこともあると思います。こういう時に使うのが型ガードです。

TSの環境を整える

上記の型ガードとは?ということは知っていたのですが実際に例題にぶつからないと僕は理解できない派なので型ガードの恩恵を感じるためにサンプルの環境を作って理解したいなって話です。別に以下のような環境を整えずとも大丈夫なのですがただ僕がやってみたかっただけです。

TS 4.1 を導入する。

2020年11月19日にTypeScript4.1がリリースされました。更にそのTS 4.1でnoUncheckedIndexedAccessというオプションが追加されました。これらを導入したいと思います。

npm install - D typescript@4.1.3

tsconfig.jsonを編集する。

noUncheckedIndexedAccessのオプションを今回使用したいので追加し、trueにしましょう。

{
  "compilerOptions": {
    // 他のオプションは割愛
    "noUncheckedIndexedAccess": true
  },
}

undefined の可能性があるプロパティへのアクセスを厳密にしてくれるのが 今回追加したnoUncheckedIndexedAccess オプションです。

ここまでで環境を大体整えれたので実際にサンプルコードで見てみたいと思います。

// App.tsx

function App() {
  return (
    <div className="App">
      <header className="App-header">
        {HogeData && (
          <HogeComponent description={HogeData[id].description ?? ""} />
        )}
      </header>
    </div>
  );
}

export default App;
// HogeData.ts

export const HogeData: {
  [key: string]: {
    description: string;
  };
} = {
  first: {
    description: "ほげほげほげ",
  },
  second: {
    description: "ふがふがふが",
  },
};

上記の例をみてください。ちなみにHogeComponentは受け取ったdescriptionを描画するだけのコンポーネントです。

上記の場合、App.tsxはTSに怒られます。

<HogeComponent description={HogeData[id].description ?? ""} /> のところですね。HogeDataは今回の例ではidがfirstsecond の場合のみdescriptionをstring型で返します。しかしidは空文字列の時や想定されていない文字列が渡った場合HogeData[id] はundefinedになり、type errorになってしまいます。またnoUncheckedIndexedAccess のおかげでバッチリvscode上で怒られます。

以下のようにopptionalにするとtype errorは収まります。

{HogeData && (
  <HogeComponent description={HogeData[id]?.description ?? ""} />
)}

しかし実際にはidには指定のものしか絶対渡らない状況であり、HogeDataが存在すれば、HogeData[id]undefinedになり得ない状況だとしましょう。しかしこの場合でもTSはtype errorで怒ってきます。

改善する

HogeData[id]を変数化。

const descriptionData = HogeData[id];

HogeData[id]を変数に入れることで、

if (descriptionData)

descriptionDataundefinedではない! と、TSは認識できるのでその後に

descriptionData.description

を使っても「undefinedじゃないの?」といったerrorは出なくなります。

またnull合体演算子で 空文字列を保証する必要も無くなります。

最終的なコード

function App() {
  const descriptionData = HogeData[id];
  return (
    <div className="App">
      <header className="App-header">
        {descriptionData && (
          <HogeComponent description={descriptionData.description} />
        )}
      </header>
    </div>
  );
}

これでnoUncheckedIndexedAccess のチェックでもerrorは起こりません。

今回は型ガードで制限しつつ、undefinedの怒られを回避できるような例を書いてみました。

それでは。

Discussion