TypeScriptを書いていると、anyって便利だけどなんか怖い…という感覚、ありませんか?

anyとunknownって何が違うの?どっちも「なんでも入る型」じゃないの?
anyを使ったら動いたけど、これで本当に合ってるのかわからない…
unknownって型ガードが必要って言われたけど、どう書けばいいの?

この記事では、anyとunknownの本質的な違いを整理したうえで、「どちらをどんな場面で使うか」の判断基準まで説明します。

この記事は次のような方におすすめです。

この記事はこんな人におすすめ!
  • TypeScriptでanyを使ったことはあるが、「本当にこれでいいのか」と不安を感じている方
  • anyとunknownの違いがなんとなくしかわからない方
  • unknownを使うべきと聞いたが、具体的な書き方がわからない方
  • プリミティブ型や型推論はひととおり学んだ、TypeScript初心者の方

この記事を読むと、anyとunknownの使い分けの基準がつかめて、「なんとなくanyを使う」状態から抜け出せます。

それでは、順を追って詳しく見ていきましょう!

anyとunknownはどちらも「何でも受け取れる型」

anyとunknownはどちらも「何でも受け取れる型」

まず、anyとunknownには共通点があります。どちらも、どんな値でも代入できる型です。

let a: any;
a = 42;          // OK
a = "こんにちは"; // OK
a = true;        // OK

let b: unknown;
b = 42;          // OK
b = "こんにちは"; // OK
b = true;        // OK

どちらも代入の段階ではエラーになりません。

「じゃあ同じじゃないの?」と思うかもしれませんが、違いが出るのは「代入した後、その値を使おうとした瞬間」です。ここが、この2つの型の本質的な分かれ目になります。

anyとunknownの本質的な違い — 型チェックが効くかどうか

anyとunknownの本質的な違い — 型チェックが効くかどうか

anyを使うと、型チェックが無効になる

anyを使うと、TypeScriptの型チェック機能が実質的にオフになります。どんな操作をしようとしてもエラーが出ません。

let value: any = "こんにちは";

// 文字列っぽく使っても…
console.log(value.toUpperCase()); // OK(TypeScriptはエラーを出さない)

// 数値っぽく使っても…
console.log(value.toFixed(2));    // OK(TypeScriptはエラーを出さない)

「エラーが出ないならいいじゃないか」と思うかもしれません。でも、上のコードでvalue.toFixed(2)を実行すると、実行時にエラーになります。文字列にはtoFixedというメソッドがないからです。

anyの問題は「コンパイル時にエラーを検知できない」こと。TypeScriptを使っているのに、JavaScriptのときと同じ状態に戻ってしまうイメージです。

unknownは型チェックを保ったまま受け取れる

一方、unknownを使うと「受け取りはするけど、使うには確認が必要」という動作になります。

let value: unknown = "こんにちは";

// そのまま使おうとするとエラーになる
console.log(value.toUpperCase()); // エラー:'value' is of type 'unknown'

「使えないなら意味ないじゃないか」と思うかもしれませんが、これは意図的な設計です。unknownは「型が不確かな値は、確認してから使ってください」とTypeScriptが要求している状態です。

なかむぅ
なかむぅ
確認(型の絞り込み)をすれば、きちんと使えるようになります。その方法を次の節で説明します。

unknownを実際に使うには「型の絞り込み」が必要

unknownを実際に使うには「型の絞り込み」が必要

unknownの値を使うには、「この値はこういう型ですよ」とTypeScriptに教えてあげる必要があります。これを型の絞り込みと呼びます。

typeofで絞り込む

最もよく使う方法が、typeof演算子を使った絞り込みです。

function printValue(value: unknown) {
  if (typeof value === "string") {
    // この中ではvalueはstring型として扱える
    console.log(value.toUpperCase()); // OK
  } else if (typeof value === "number") {
    // この中ではvalueはnumber型として扱える
    console.log(value.toFixed(2)); // OK
  }
}

typeof value === "string" というチェックを通過した後は、TypeScriptがvalueをstring型だと認識してくれます。このように「条件で絞り込むことで型を確定させる」仕組みを型ガードと言います。

instanceofで絞り込む

オブジェクトやクラスのインスタンスを確認したい場合はinstanceofを使います。

function handleError(error: unknown) {
  if (error instanceof Error) {
    // この中ではerrorはError型として扱える
    console.log(error.message); // OK
  }
}

try-catchのcatch節でエラーを受け取るときによく使うパターンです。

型アサーション(as)で絞り込む場合の注意点

「絞り込みが面倒だから、asで強制的に型を指定すればいいのでは?」と思う方もいるかもしれません。

let value: unknown = "こんにちは";
const str = value as string; // TypeScriptはエラーを出さない
console.log(str.toUpperCase()); // OK

これは動きますが、asは型チェックをスキップするため、使い方を誤ると実行時エラーの原因になります

let value: unknown = 42;
const str = value as string; // 本当は数値なのに…
console.log(str.toUpperCase()); // 実行時エラー!

asを使うのは「自分が型を確実に把握している場面」に限定するのが安全です。typeof/instanceofによる絞り込みを先に検討するようにしましょう。

anyとunknownの違いを表で整理する

anyとunknownの違いを表で整理する

ここまでの内容をまとめます。

比較項目 any unknown
何でも代入できるか ✅ できる ✅ できる
型チェックが効くか ❌ 効かない ✅ 効く
そのまま操作できるか ✅ できる(危険) ❌ 絞り込みが必要
TypeScriptの恩恵を受けられるか ❌ 受けられない ✅ 受けられる
安全性 低い 高い

一言でまとめると、「型が不確かな値を受け取りたいときは、anyよりunknownを使う方がTypeScriptらしい書き方」です。

anyをいつ使っていいのか — やむを得ない場面を整理する

anyをいつ使っていいのか — やむを得ない場面を整理する

「anyはダメ」とよく言われますが、現実のコードではanyが出てくる場面もあります。すべてがNG というわけではなく、「やむを得ない場面」を知っておくことが大切です。

anyを使ってもよいと判断できる代表的な場面は以下の通りです。

JavaScriptからTypeScriptへの移行途中

既存のJSコードを段階的にTS化しているときに、一時的にanyを使うことがあります。「まずコンパイルを通す、型は後から整える」という移行戦略の一環として許容されます。

型定義ファイルが存在しないライブラリを使うとき

外部ライブラリの中には、TypeScriptの型定義(.d.tsファイル)が提供されていないものがあります。この場合、一時的にanyで受け取ることがあります。

TypeScriptに詳しいチームが意図的に選択するとき

型定義が複雑すぎる場面で、あえてanyを使ってシンプルにするケースもあります。ただし、この判断はTypeScriptへの理解が深まってから行うものです。

開発中は、「anyを使いたくなったら、まずunknownで代替できないか考える」習慣をつけておくと、TypeScriptの恩恵をより受けやすくなります。

【付録】さらに学びを深めるためのリソース


さらにTypescriptの学習を進めたい方のために、いくつかのリソースを紹介します。
これらのリソースを活用することで、TypeScriptの型システムについてより深い知識を得ることができるでしょう。

おすすめの書籍

ゼロからわかる TypeScript入門


技術評論社から出版されている「ゼロからわかる TypeScript入門」は、プログラミング初心者や本職プログラマーではない方を主な対象にした入門書です。

変数・条件分岐・ループといった基本から、クラスやインターフェース、モジュールまで段階的に学べる構成になっています。最終章ではWeb APIとJSONを使った非同期Webアプリの作成も体験できるので、「実際に動くものを作る」ところまで到達できます。

プロを目指す人のためのTypeScript入門


技術評論社の「プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで」、通称 ブルーベリー本 です。
JavaScriptの仕様とTypeScript独自の機能を両方押さえつつ、リテラル型・ユニオン型・keyof型・ジェネリクスなど、高度な型表現まで踏み込んで解説しています。TypeScriptの型システムの表現力を本格的に学べる一冊です。

オンラインで参照できる公式ドキュメント

TypeScript公式ハンドブック


https://www.typescriptlang.org/docs/
TypeScriptの公式ドキュメントです。
intersection型を含む、すべての型システムの機能について詳細な説明があります。

TypeScript Deep Dive


https://basarat.gitbook.io/typescript/
TypeScriptの深い部分まで掘り下げて解説しているオンラインブックです。
無料で読むことができ、intersection型についても詳しく説明されています。

TypeScriptの学習は終わりがありません。
新しい機能が常に追加され、より良い書き方が発見されています。
継続的に学習を続けることで、より良いTypeScriptプログラマーになれるはずです。


まとめ:迷ったらunknownから始めよう

まとめ:迷ったらunknownから始めよう

この記事で押さえてほしいポイントを整理します。

  • anyとunknownはどちらも「何でも代入できる型」という点では同じ
  • 違いは「型チェックが効くかどうか」。anyは型チェックが無効になり、unknownは保たれる
  • unknownを使うにはtypeofinstanceofによる型の絞り込みが必要
  • as(型アサーション)は絞り込みの代替になるが、誤用すると実行時エラーの原因になるため注意
  • anyが必要になる場面はあるが、まずunknownで代替できないかを考えるのが基本

型が不確かな値を受け取りたいとき、最初にunknownを使うことを習慣にするだけで、TypeScriptの安全性が格段に高まります。

※本記事の本文案はAIを活用して作成していますが、記載している内容およびコードは筆者が実際に調査、検証・実行し、内容の正確性を確認した上で公開しています。