TypeScript | 基礎文法:変数・基本型 – unknown型との違い

TypeScript
スポンサーリンク

any型とunknown型は「似て非なるもの」

どちらも「どんな値でも代入できる型」ですが、性格は真逆です。
ざっくり言うと、

  • any型:型チェックをほぼ無効化する「なんでもアリモード」
  • unknown型:何でも受け取るけれど「使う前に必ずチェックさせる安全モード」

どちらも「受け取る側」としては柔軟ですが、「使う側」としての厳しさがまったく違います。


any型の振る舞いと問題点

何でも代入できて、どこにでも代入できる

let value: any;

value = 123;
value = "hello";
value = { a: 1 };

let num: number = value;    // OK
let str: string = value;    // OK
TypeScript

any は「どんな型の値も受け取れる」うえに、「その値をどんな型の変数にも代入できる」型です。
つまり、TypeScriptの型チェックをほぼスキップしてしまいます。

メソッド呼び出しも全部通ってしまう

let value: any = "hello";

value.toUpperCase();  // OK(コンパイルは通る)
value.nonExist();     // これもコンパイルは通る(実行時に落ちる可能性)
TypeScript

any に対しては、存在しないプロパティやメソッドを呼んでもコンパイルエラーになりません。
「コンパイル時に守ってくれるはずのもの」が、ほぼ全部オフになるイメージです。


unknown型の振る舞いと特徴

「何でも受け取る」が「そのままでは使えない」

let value: unknown;

value = 123;
value = "hello";
value = { a: 1 };

let num: number = value; // エラー
TypeScript

unknown も「どんな値でも代入できる」点では any と同じです。
ただし、unknown をそのまま他の型に代入したり、メソッドを呼んだりすることはできません。

let value: unknown = "hello";

// value.toUpperCase(); // エラー: 'value' is of type 'unknown'
TypeScript

コンパイラは「中身が何か分からないから、勝手に触るな」と止めてくれます。

型ガードで「安全を証明」すれば使える

let value: unknown = "hello";

if (typeof value === "string") {
  value.toUpperCase(); // OK(このブロック内では string とみなされる)
}
TypeScript

unknown は、「使う前に型チェック(絞り込み)をしなさい」ということを強制する型です。
この「チェックを強制する」という点が、anyとの決定的な違いです。


any型とunknown型の決定的な違い

「自由度」と「安全性」のトレードオフ

よく整理された比較として、こんな関係があります。

  • any
    • どんな値でも代入できる
    • どんな型の変数にも代入できる
    • どんな操作も許される(メソッド呼び出しなど)
    • 型安全性は低い(型チェックを回避)
  • unknown
    • どんな値でも代入できる
    • そのまま他の型に代入できない
    • そのままメソッドを呼べない
    • 型チェック(絞り込み)を強制するので型安全性が高い

同じ「何でも受け取れる」でも、
any は「何でもできるけど、何も守ってくれない」
unknown は「何でも受け取るけど、勝手なことはさせない」
という真逆の性格を持っています。


実際のコードでの違いを並べて見る

代入の違い

let a: any = "hello";
let u: unknown = "hello";

let s1: string = a; // OK
// let s2: string = u; // エラー: 'unknown' を 'string' に割り当てられない
TypeScript

any はどこにでも流し込めますが、unknown は「ちゃんと中身を確認してからにして」と止めてくれます。

メソッド呼び出しの違い

let a: any = "hello";
let u: unknown = "hello";

a.toUpperCase(); // OK(コンパイルは通る)
// u.toUpperCase(); // エラー: 'u' is of type 'unknown'
TypeScript

unknown は、「本当に string だと分かるまでは toUpperCase を呼ばせない」というスタンスです。


初心者が身につけたい「使い分けの感覚」

デフォルトで選ぶべきは unknown

「どんな値が来るか分からない」状況で、
・型安全性を捨ててもいいから、とにかく動かしたい → any
・型安全性は守りたい。面倒でもチェックしてから使いたい → unknown

という選択になります。

TypeScriptの目的を考えると、基本的には unknown を選ぶ方が健全です。
any は「型安全性を捨てる代わりに自由を得る」最後の手段としてだけ使う、くらいの感覚でちょうどいいです。

具体的な指針(ざっくり)

外部から来るデータ(APIレスポンス、JSONパース結果など)
→ まず unknown で受けて、型ガードやバリデーションで絞り込む

古いコードや型定義のないライブラリを一時的に動かしたい
→ やむを得ず any を使うことはあるが、範囲を小さく閉じ込める

「とりあえずエラーを消したいから any」
→ 一番危険なパターン。unknown か、ちゃんとした型定義を検討するべき


まとめ:anyは「型チェックOFF」、unknownは「型チェックONのまま不明」

最後に一番大事なイメージだけ残すと、こうです。

any:
「この値について、TypeScript は何も文句を言わないで」
→ 型チェックOFF、守りゼロ

unknown:
「この値が何かは分からないけど、勝手に触らせないで」
→ 型チェックONのまま、「使う前に必ず確認させる」

「分からないもの」を扱うときに、
安全側に倒したいなら unknown、
安全性を犠牲にしてでも突っ走りたいなら any。

あなたがこれからTypeScriptを「長く気持ちよく」使っていきたいなら、
迷ったときの合言葉は、
「分からないものは unknown、どうしても必要なときだけ any」。
ここを軸にしておくと、型の世界で迷子になりにくくなります。

タイトルとURLをコピーしました