【TypeScript入門】asとは?型アサーションとは? | 型アノテーションとの違いも解説

Type-Assertion

こんにちは、フロントエンドエンジニアのまさにょんです。

今回は、TypeScriptでの「as」(Type-Assertion)について解説していきます。

「as」とは何か?なぜ「as」なのか?

TypeScriptだとでてくる「 as 」とは何なのでしょうか?

迷えるTypeScript使いの指南書『サバイバルTypeScript』から引用します。

TypeScriptには、型推論を上書きする機能があります。

その機能を型アサーション(type assertion)と言います。

TypeScriptコンパイラーはコードをヒントに型を推論してくれます。

その型推論は非常に知的ですが、場合によってはコンパイラーよりもプログラマーがより正確な型を知っている場合があります。

そのような場合は、型アサーションを用いるとコンパイラーに型を伝えることができます。

型アサーションはコンパイラに「私を信じて!私のほうが型に詳しいから」と伝えるようなものです。

引用元: 型アサーション「as」(type assertion) – サバイバルTypeScript

上記に明記されているように、

「 as 」は「型アサーション」(Type-Assertion) と言うTypeScriptの機能であり、

「型推論」された変数の「型」を宣言的・明示的に「上書きする」ための記法です。

ちなみに「Assertion」は、 主張, 断言, 明言 と言った意味の英単語です。

英語のType-Assertionを直訳すると「型の明言」と言ったところなので、「型」宣言的・明示的に「上書きする」ための機能であることをそのまま表してくれています。

次に、なぜ「 as 」なのか?

これは「 Assertion 」の「 As 」と英単語の「 as 」、両方をかけていると思われます。

英語の「 as 」は「 = 」のニュアンス(Nuance)を持っています。

なので英語ネイティブの感覚からすると「 as 」を使って「型」を宣言するのは、宣言的・明示的に開発者が「 = 」で「型」を後から結びつけている(上書きする)ようなものだと思います。

「 as 」(Type-Assertion)は、どんなタイミングで必要なのか?

「 as 」の意味や、なぜ「 as 」なのか理解したところで、実際のところ「 as 」は、どんなタイミングで必要になってくるのか気になりませんか?

「 as 」が必要になるタイミングは、決まっています。

それはTypeScriptのCompilerによる「型推論」が裏目にでるケースです。

それではCode上で、「型推論」が裏目にでるケースを見ていきましょう!

// < Error-Pattern >

// 1. TypeScriptのCompilerが「 {} 」(空-Object)と判定をする!
const robo = {};

// 2. 「key & value」を追加しようとすると「型-Error」が発生する!
robo.robotama = 'ロボ玉';

上記のようなCompilerによる「型推論」(初期の型定義)から上書きしたい場合に「 as 」を使います!

具体的には、次のように記述します。

// < Success-Pattern >

// 1. 事前にkey & value を定義する => Data-Fetchなどで後から追加される値を定義する!
interface Robotama {
    robotama: string;
}

// 2. 「 as 」を使って「型推論」を上書きする!
const robo = {} as Robotama;

// 3. Success!
robo.robotama = 'ロボ玉'; 

上記の処理を日本語でまとめると、次のようになります。

Success-Pattern-処理-言語化
1. TypeScriptのCompilerが「 {} 」(空-Object)と判定をする => 「型推論」であり「初期の型定義」
2. しかし、このObjectには、後からDataが追加される予定である。
3. そこで、Data-Fetchなどで後から追加されるであろう値を定義した「型」を用意する。
4. 「 as 」で「型推論」を上書きする!
5. 「 as 」上書きされた「宣言的・明示的な型」によって、Success!

ダブル・アサーション(Double-Assertion)

「 as 」は、二重がけすることができます。

「any」や「unknown」を通すことで、型を自由にAssertionできます。

ただ、この技はErrorの温床に可能性が高いので、基本的に使用しない方がいいと思います。

TypeScriptで型-Checkしている意味がなくなるわけですから・・・

ただし、場合によっては有効な場合もあります。

// < Double-Assertion >

const numValue = 123;

// 1.「any」を通した「Double-Assertion」で型-Check-Through!
const strValue = numValue as any as string; 

// 2.「unknown」を通した「Double-Assertion」で型-Check-Through!
const booleanValue = numValue as unknown as boolean;

// 3. 基本的にErrorの温床になるので使用しない!
// TypeScriptを使用する意味がなくなる・・・

// 4. 場合によっては、有効な場合も、、、

// 5. anyを間に挟むことで「Event」を「HTMLElement」として扱える!
const eventHandler = (event: Event) => {
    let element = event as any as HTMLElement;
}

型-アサーションとキャストは違います!

Type-Assertion(型-アサーション)とCast(キャスト)は違います!

型アサーションは、他の言語のキャストに似ています。

キャストとは、実行時にある値の型を別の型に変換することです。

型アサーションは、実行時に影響しません。

値の型変換はしないのです。

あくまでコンパイル時にコンパイラーに型を伝えるだけです。

コンパイラーはその情報を手がかりに、コードをチェックします。

型アサーションはキャストではないため、TypeScriptでは型アサーションをキャストとは呼ばないことになっています。

実行時に型変換をするには、そのためのロジックを書く必要があります。

引用元: 型アサーション「as」(type assertion) – サバイバルTypeScript

今までの説明や、上記の引用に記述のあるとおり、

Type-Assertionは「型の宣言的・明示的な上書き」であり、Castは「実行時の型を変換する」ことです。

// < Cast(型変換) >

// 1. Number() でCast(型変換)している!
const num: number = Number('123');

console.log(typeof num); // number

console.log({num}); // {num: 123}

型アサーションと型アノテーションは違います!

Type-Assertion(型-アサーション)とType-Annotation(型-アノテーション)は名前が似ていますが、違います!

型アサーションと型アノテーション(type annotation)は名前が似ているためかしばしば混同されます。

本書では型アノテーションを「型注釈」と表記しています。

この2つはTypeScriptの異なる機能です。

型注釈は、コンパイラーに「この変数に代入できるのはこの型だよ」と伝えるものです。

コンパイラーは型注釈をヒントに、その型に値が代入可能かどうかをチェックし、代入できないことが分かり次第報告してきます。

一方、型アサーションはコンパイラーに「君はこの型だと思ってるかもしれないけど、本当はこの型だよ」と型推論の不正確さを伝えるものです。

引用元: 型アサーション「as」(type assertion) – サバイバルTypeScript

今までの説明や、上記の引用に記述のあるとおり、

Type-Assertionは「型の宣言的・明示的な上書き」であり、Type-Annotationは「型を伝える」ことです。

// < 型推論-型注釈-TypeAssertion-比較 >

// 1. 型推論: Compilerは、stringと型推論する!
const robotamaString = 'ロボ玉';

// 2. 型注釈: あらかじめ「型」を定義する => 型に注釈(説明)を付けて、Compilerに伝える!
let robotamaFlag: boolean;

// 3. TypeAssertion: 型推論で「 never[] 」と推測されていたが「 as 」で上書きする!
const robotamaStrArray = [] as string[] ;

robotamaStrArray.push('ロボ玉');

ちなみに「Annotation」は、注釈, 注記 という意味の英単語です。

まとめ

  1. 「 as 」は「型アサーション」(Type-Assertion) と言うTypeScriptの機能
  2. 「 as 」を使うと「型推論」された変数の「型」を宣言的・明示的に「上書きする」ことができる
  3. 英語の「 as 」は「 = 」のニュアンス(Nuance)を持っている
  4. 「 as 」が必要になるタイミングは、TypeScriptのCompilerによる「型推論」が裏目にでる時
  5. 「型推論」という「初期の型定義」を上書きしたい場合に「 as 」を使用する

TypeScript書籍

参考・引用

  1. 型アサーション「as」(type assertion) – サバイバルTypeScript
  2. TypeScriptの as って何です?(型アサーションについて) – Qiita

最近の投稿