Menu

TypeScriptのas: 型アサーションとキャストを解説

as キーワードは、値を別の型として扱うようTypeScriptに伝えます。キャストではありません。実行時には何も変換もチェックもされません。as と山かっこの構文、コンパイラーが許可する範囲、unknown を経由する二重アサーション、型ガードのほうが向いている場面を解説します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

value as Type は型アサーションで、value を Type として扱うようTypeScriptに伝えます。キャストと呼ばれることがありますが、コンパイラーへの指示にすぎません。JavaScriptの出力からは消え、実行時には何も変換せず、何もチェックしません。

これが典型的な使い方です。コンパイラーにはわからない値の情報(ここではJSONの形)を自分が知っていて、それを伝えています。間違っていても何も警告されません。以下では、それが何を意味するか、そして実行時のチェックのほうがよいのはどんなときかを説明します。

as と山かっこの構文

同じアサーションに2つの書き方があります:

const someValue: unknown = "hello";
const a = someValue as string;   // as syntax
const b = <string>someValue;     // angle-bracket syntax, same meaning

山かっこの形は .tsx ファイルでは使えません。<string> がJSXのタグとして読まれてしまうからです。どこでも as を使えば、この問題は起きません。アサーションの結合は弱いので、式を続けるときはかっこで囲みます: (value as string).length。

アサーションは値を変換しない

ここが実際のバグにつながる部分です。アサーションが変えるのは値についてのコンパイラーの認識であって、値そのものではありません:

コンパイラーは asserted を number だと信じているので、asserted + 1 は算術演算として型チェックを通ります。実行時には文字列 "42" のままなので、JavaScriptは文字列を連結します。値の型を変えるには変換します: Number(x)、String(x)、Boolean(x)、BigInt(x)、new Date(x)。変換関数の比較は 文字列を数値に変換 のページにあります。

したいこと書き方実行時の効果
知っている型をコンパイラーに伝えるx as Tなし
文字列を数値にするNumber(x)、parseInt(x, 10)変換する
何でも文字列にするString(x)、`${x}`変換する
先に型をチェックする型ガード、typeof、instanceofチェックする

コンパイラーが許可する範囲

as は無制限ではありません。TypeScriptが x as T を許可するのは、どちらかの型がもう一方に代入できるときです。広げる方向("a" as string、dog as Animal)も狭める方向(animal as Dog、unknown as User)も問題ありません。型にまったく重なりがなければ拒否します:

コンパイラーは index.ts(3,11): error TS2352: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. を報告します。メッセージ自体が抜け道を示しています: input as unknown as number。この二重アサーションはコンパイルできますが、実行時には上の例とまったく同じように間違っています。これが必要だと感じたら、たいていは変換(Number(input))か、型を見直すのが正しい直し方です。

オブジェクトでは重なりのルールがゆるくなります。プロパティの一部を持つオブジェクトリテラルは受け入れられるので、as は不完全なオブジェクトを黙って通してしまいます:

型注釈(const draft: User = { name: "Ada" })や satisfies User なら、足りない email を報告します(TS2741)。オブジェクトリテラルに as を使うのは本当にあとで埋めるつもりのときだけにして、完全なオブジェクトを作るほうを選びましょう。

as const は別物

as const はアサーションに見えますが、型をゆるめるのとは逆のことをします。リテラルをできるだけ狭い型にします。文字列はリテラル型のまま、配列は readonly のタプルになり、オブジェクトのプロパティは readonly になります。

コンパイラーに見えないことを主張するのではなく、リテラルを正確に表すだけなので安全です。(isSize の中の sizes as readonly string[] は広げる方向のアサーションで、これも安全です。includes が任意の文字列を受け付けるようになります。)詳しくは リテラル型 を参照してください。

型ガードのほうが向いている場面

as は主張で、型ガードはチェックです。データがコードの外から来る境界(JSON、fetch、localStorage、ユーザー入力、メッセージ)では、その主張が間違っていることがあり、アサーションは境界でのわかりやすいエラーを、どこか別の場所でのわかりにくいエラーに変えてしまいます。

似たように見える方法の大まかな使い分けです:

方法コンパイル時のチェック実行時のチェック使う場面
型注釈 const x: T = ...あり(完全)なし値を自分で作る
satisfies Tあり(完全)、推論された型を保つなしオブジェクトリテラル、設定
as T「型に重なりがあるか」だけなしコンパイラーより型をよく知っている
x!null / undefined を取り除くだけなし値が設定済みだとわかっている
型ガード x is T型ガードの本体は普通のコードあり外から来るデータ

as の正しい使い道は2つ残ります。コンパイラーが追えないものを絞り込む場合(2行前にセットした Map のエントリー、型のないライブラリからの値)と、部分的なテスト用データを作るテストコードです。どちらも小さく保ち、その主張が正しいとわかっている場所の近くに置きましょう。

よくある質問

TypeScriptの as は何をしますか?

value as Type は型アサーションで、ここから先は value を Type として扱うようコンパイラーに伝えます。コンパイル後のJavaScriptからは取り除かれるので、変換も実行時のチェックも行いません。アサーションが間違っていれば、あとでその間違った型が使われた場所でプログラムが失敗します。

TypeScriptで型をキャストするには?

TypeScriptには実行時のキャストはありません。コンパイラーより自分のほうが型をよく知っているときに、as(または古い <Type>value)で静的な型を変えます。値を実際に変換するには関数を呼びます: Number("42")、String(42)、Boolean(x)、new Date(text)。

TypeScriptの「as unknown as」とはどういう意味ですか?

二重アサーションです。TypeScriptは2つの型にまったく重なりがないとき x as T を拒否します(エラー TS2352)が、先に unknown を経由するとそのチェックを回避できます。unknown へも unknown からも何でもアサーションできるからです。その値の型チェックを完全に止めてしまうので、テストや、別の方法で型を確認したコードだけに使いましょう。

TypeScriptの as と山かっこの違いは何ですか?

意味は同じです。<string>value と value as string は同じアサーションです。山かっこの形はJSXとぶつかるので .tsx ファイルでは使えず、そのため誰もが as の形を使います。

as と satisfies の違いは何ですか?

as は推論された型を上書きし、ほとんどチェックしません(プロパティが足りなくても通ります)。satisfies は値を型と照らし合わせてチェックし、プロパティの不足や余分を報告しつつ、推論された正確な型を保ちます。オブジェクトリテラルには satisfies を使い、as は本当にコンパイラーより型をよく知っているときだけにしましょう。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める