👀

型アサーション【個人学習まとめ】

に公開6

型アサーション

開発者が特定の変数について、TypeScript の型チェッカーよりも詳しい型情報を持っている場合に、コード内で型の情報を明示することを型アサーションと呼びます。
型アサーション

構文

変数名 as 型名 という形式で記述します。
変数名には上書きしたい変数を指定し、型名には指定した変数に割り当てたい型を指定します。
型アサーションにより、指定された変数に新しい型を明示的に適用することができます。

では例を見てみましょう。

let input: unknown;

//ユーザーの操作やAPI処理など
・・・
//変数inputの型をstring型にアサーション
let result: string;
result = input as string;

変数inputunknown型です。変数宣言後に何かしら処理を行い、最終的にはstring型になることを開発者は理解しています。
しかし、TypeScript の型推論はそのことを推論できないとします。

この時に型アサーションを利用することで、変数inputstring型として扱わせることができます。

型アサーションは、サブタイプとスーパータイプの関係にある型の間でしか利用することはできません。
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 に伝えています。

非アサーション

開発者が該当コードの変数部分が、絶対にnullundefinedにならないことを確信している場合に、その情報を 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!を利用することで、変数datanullではないことを断定しています。

これによって、変数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

junerjuner

querySelector 使うのであるなら 型引数を持っているので querySelector<HTMLInputElement>(...) すればよかったのでは……?
(であれば nullable なので nullチェックも強要されます

ろろろろろろ

確かにおっしゃる通りですね🤔
ご指摘の通りquerySelector<HTMLInputElement>(...)を使う方がサンプルコードとしては正しいコードですね!
ただ、今回は「戻り値がnullも含まず、絶対にHTMLInputElementである!」ということ前提の例として、あえてas HTMLInputElementを使っていました。
ご指摘ありがとうございました!いただいたコメントでより深く考えるきっかけになり、勉強になります!

junerjuner

型引数を持たないのだと document.getElementById(...) (id で取得)や document.getElementsByClassName(...) (クラス名で取得) や document.evaluate(...) (XPath で取得)などあります。

ろろろろろろ

おお、こんなにいろいろあるんですね!document.evaluate(...) の方法は初めて知りました。またしても私の知識不足ですね……!
自分の環境でも試してみながら学習して、記事も見直してみます!!

ろろろろろろ

リンクありがとうございます!読ませていただきました。
querySelectorは汎用的すぎる…勉強になりました。
この件はじっくりと時間をとって再勉強してみます!いつもありがとうございます!