##この記事で学べること
- Non-null assertion operator(例: document.getElementById("〇〇")!)
- Type Assertions(例: document.getElementById("〇〇") as HTMLElement)
TypeScript入門者はもちろん、JavaScriptしか触ったことのないプログラミング初心者も対象です。
Non-null assertion operatorとは
私がTypeScriptに入門して最初に躓いたのがDOM操作でした。TypeScriptはJavaScriptより型に厳しいので、同じコードを書いてもTypeScriptだと警告が出ることがあります。簡単な例を紹介します。
// Javascriptファイル
const input = document.getElementById("usernameInput");
input.placeholder = "ユーザー名を入力してください";
// Typescriptファイル
const input = document.getElementById("usernameInput");
input.placeholder = "ユーザー名を入力してください"; // 警告が出る
警告文は、inputは__HTMLElement__と__null__を値として取る可能性があるオブジェクトであり、そうしたnullを取りうるオブジェクトにplaceholderプロパティは使用できない、という意味になります。
なぜnullを含むのかというと、getElementByIdメソッドの引数をタイポしていた場合それが返るからです。引数の文字列が正しいかどうか、つまりHTMLファイルの中に実際に
<input id="usernameInput">
があるかどうかまではTypeScriptコンパイラーは判断できないため、代わりにnullが返る可能性を憂慮してくれています。
このとき、引数の文字列が正しいと分かっている場合、TypeScriptコンパイラーに対して、「nullの心配はない」と教えてあげる必要があります。その方法が__Non-null assertion operator__でして、__!__を末尾につけて書きます。
これで、inputはHTMLElementだけを取りうるオブジェクトになりました。ただ、placeholderにまだ警告が出てます。
Type Assertionsとは
警告文はだいたいこんな意味になります。
const taro = {
name: "太郎",
age: 22
}
taro.language = "English" // 'language'というプロパティは'taro'に存在しない
もともとplaceholderは、__HTMLInputElementオブジェクト*またはHTMLTextAreaElement__オブジェクトがもつプロパティです。つまり、inputタグまたはtextareaタグにしか使えません。
(注: 正確には、HTMLInputElementというインターフェースが適用されたオブジェクトです)
<input placeholder="ユーザー名を入力してください。">
<textarea placeholder="ご感想など"></textarea>
一方、getElementByIdメソッドは__HTMLElement__オブジェクトを返します。これはHTMLInputElementオブジェクトとHTMLTextAreaElementオブジェクトを含むあらゆるHTML要素の親にあたるものです。
したがって、警告文は「placeholderプロパティを更新したければどういうDOMか具体的に教えて欲しい」みたいに読み替えられます。では、__Type Assertions(型注釈)__を使って「それはinputだ」と教えてあげましょう。
Type Assertionsには__as__を使う方法と__< >__を使う方法があり、どちらを使うかは好みだと思います。
const input = document.getElementById("usernameInput") as HTMLInputElement;
input.placeholder = "ユーザー名を入力してください。"
const input = <HTMLInputElement>document.getElementById("usernameInput");
input.placeholder = "ユーザー名を入力してください。"
なお、一行で書くには__( )__で囲む必要があるのと、注釈をつけることでnullの可能性は否定されるため、Non-null assertion operator は省略できます。
(document.getElementById("usernameInput") as HTMLInputElement).placeholder = "ユーザー名を入力してください。";
(<HTMLInputElement>document.getElementById("usernameInput")).placeholder = "ユーザー名を入力してください。";
ちなみにReactなどでJSXを書く場合、コンポーネントと混同しやすいため、as形式しか使えません。