型アサーション【個人学習まとめ】
型アサーション
開発者が特定の変数について、TypeScript の型チェッカーよりも詳しい型情報を持っている場合に、コード内で型の情報を明示することを型アサーションと呼びます。
型アサーション
構文
変数名 as 型名
という形式で記述します。
変数名
には上書きしたい変数を指定し、型名
には指定した変数に割り当てたい型を指定します。
型アサーションにより、指定された変数に新しい型を明示的に適用することができます。
例
では例を見てみましょう。
let input: unknown;
//ユーザーの操作やAPI処理など
・・・
//変数inputの型をstring型にアサーション
let result: string;
result = input as string;
変数input
はunknown
型です。変数宣言後に何かしら処理を行い、最終的にはstring
型になることを開発者は理解しています。
しかし、TypeScript の型推論はそのことを推論できないとします。
この時に型アサーションを利用することで、変数input
がstring
型として扱わせることができます。
型アサーションは、サブタイプとスーパータイプの関係にある型の間でしか利用することはできません。
string
型をnumber
型に変更するなどといったことはできません。
let stringValue: string;
//string型をnumber型に型アサーションしようとすると・・・
let numberValue: number;
numberValue = stringValue as number;
→ 型 'string' から型 'number' への変換は、互いに十分に重複できないため間違っている可能性があります。意図的にそうする場合は、まず式を 'unknown' に変換してください。
実際に型アサーションが必要になるのは、DOM 操作などを行ったときに必要になります。
const elementA = document.querySelector(".someClass");
//Element | null のユニオン型
//型アサーションによる型の変更
const elementB = document.querySelector(".someClass") as HTMLInputElement;
上記例ではdocument.querySelector
から取得される要素の型が、TypeScript によって型推論が行われElement | null
型として推論されています。さらに型チェッカーは HTML 内に.someClass
が確実に存在するかどうかも判断することができないため、null
とのユニオン型として推論します。
変数elementB
では、document.querySelector
の戻り値にたいして型アサーション(as HTMLInputElement
)を適用することによて、戻り値がHTMLInputElement
であるよ!ということを TypeScript に伝えています。
非アサーション
開発者が該当コードの変数部分が、絶対にnull
やundefined
にならないことを確信している場合に、その情報を TypeScript に伝えるための構文です。
非アサーション
非 Null アサーションの構文
対象の変数名の後に!
!を付けることで適用されます。
例
では例を見てみましょう。
function fetchData() {
const resultData = Math.random() > 0.5 ? "結果だよ!" : null:
return resultData;
}
let data: string | null = fetchData();
const resultData: string = data!;
上記の変数data
の型はstring | null
であり、変数data
が null を含む可能性があります。
しかし、resultData
では非 Null アサーションdata!
を利用することで、変数data
がnull
ではないことを断定しています。
これによって、変数resultData
の型をstring
型として扱うことができます。
const アサーション
変数が読み取り専用であることを TypeScript に示すために利用されます。
const アサーション
非 Null アサーションの構文
変数宣言時に、末尾にas const
を付けると適用されます。
例
let obj = {
x: 10,
y: "こんにちは",
} as const;
上記の例では、生成したオブジェクトに対して const アサーションを行っています。
このことにより、変数obj
の各プロパティは読み取り専用となり、プロパティの値はリテラル型となります。
また、オブジェクト以外にも配列にも使用することができます。
let arr = [1, 2, 3] as const; //readonly [1, 2, 3]型
上記では、配列arr
の型はreadonly [1, 2, 3]
型と推論sれ、それぞれの要素が固定されたリテラル型になり、配列の変更も出来なくなります。
Discussion
querySelector 使うのであるなら 型引数を持っているので
querySelector<HTMLInputElement>(...)
すればよかったのでは……?(であれば nullable なので nullチェックも強要されます
確かにおっしゃる通りですね🤔
ご指摘の通り
querySelector<HTMLInputElement>(...)
を使う方がサンプルコードとしては正しいコードですね!ただ、今回は「戻り値がnullも含まず、絶対に
HTMLInputElement
である!」ということ前提の例として、あえてas HTMLInputElement
を使っていました。ご指摘ありがとうございました!いただいたコメントでより深く考えるきっかけになり、勉強になります!
型引数を持たないのだと
document.getElementById(...)
(id で取得)やdocument.getElementsByClassName(...)
(クラス名で取得) やdocument.evaluate(...)
(XPath で取得)などあります。おお、こんなにいろいろあるんですね!
document.evaluate(...)
の方法は初めて知りました。またしても私の知識不足ですね……!自分の環境でも試してみながら学習して、記事も見直してみます!!
ニュアンス querySelector / All だけはセレクタから 暗黙的に 型特定ができる場合がある為 型引数があるみたいですね……。
リンクありがとうございます!読ませていただきました。
querySelector
は汎用的すぎる…勉強になりました。この件はじっくりと時間をとって再勉強してみます!いつもありがとうございます!