1. はじめに
TypeScriptの「型安全性」を支える仕組みとして「型アサーション(as)」と「ナローイング(narrowing)」があります。
フロントエンド初心者だった頃の私はTypeScriptの型エラーが出るたびに 「asでなんとかしちゃえ!」 とエイやでやってしまったところ、先輩から「可能な限りNarrowingを実装してください!」とご指摘をいただき、以降しっかり考えるようになりました・・・😮💨
AIによるコーディングもちゃんとこの辺りを指定しないと平気でasでなんとかしがちなので、改めてまとめてみました!
2. as(型アサーション)とは
as は「この値はこの型である」と開発者がコンパイラに伝えるための構文です。
TypeScriptが型をうまく推論できないときに、「開発者が明示的に型を指定」できます。
const value: unknown = "Hello" // この時点ではvalueはunknown型
const length = (value as string).length // valueをstring型として扱う
このコードはエラーになりません。
TypeScriptは開発者を信じて、「この値はstringだ」と扱います。
3. asが型安全でない理由
TypeScriptのチェックを“無理やり”通してしまうからです。
as は、TypeScriptの型チェックを上書きしてしまうため、実際の値が異なっていてもエラーにならないことがあります。
下記コードは型チェック(コンパイル)は通りますが、実行時にエラーになる例です。
const value = "100" as number // ❌ 実際はstringだが、開発者を信じてnumberとして扱われる
console.log(value.toFixed(2)) // valueは実際stringなので当然エラー
このように、コンパイルは通るけれど実行時に落ちるという、「TypeScriptの安全性を損なう」事態が起きます。
4. Narrowing(ナローイング)を使おう
Narrowingとは、条件分岐を通じて型を安全に絞り込む仕組みです。
TypeScriptが自動的に推論してくれるので、型安全に扱えます。
function printId(id: string | number) {
if (typeof id === "string") {
console.log(id.toUpperCase()) // string型として扱われる
} else {
console.log(id.toFixed(2)) // number型として扱われる
}
}
このように書くと、TypeScriptがif文の条件をもとに、idの型を自動で推論して安全に扱えるようになります。
asは「完全に悪」ではない
TypeScriptが型を推論できないケース(DOM操作や外部データなど)では必要になることもあります。
const el = document.querySelector('#input') as HTMLInputElement
el.value = 'Hello'
こうしたケースでは、実際にその型であることが保証されている前提で使うなら問題ありません。
ただし、もし不確かな場合は、Narrowingで安全にチェックしましょう!
まとめ
TypeScriptで型エラーを起こした際に、IDEやAIは安易にasを勧めてきたりしますが、asはチェックをスキップしてしまうので極力使わないほうが良い…くらいの認識でいるのが良いかもしれません!
最後まで読んでいただきありがとうございました!🙏