型ガードとundefinedのTypeErrorについて
型ガードについてニワカであることが発覚したので復習がてら記事にしてみました。サンプルコードで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がfirst
かsecond
の場合のみ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)
でdescriptionData
はundefined
ではない! と、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