unknown と any の使い分け

anyunknown はどちらも「何でも入る型」だが、その後の扱いがまったく異なる。any は型チェックを放棄し、unknown は型チェックを強制する。この違いを理解しておかないと、TypeScript を使う意味が半減してしまう。

any は型システムの非常口

any を使うと、その変数に対するすべての型チェックが無効になる。

const value: any = "hello";

// 何をしてもエラーにならない
console.log(value.foo.bar.baz);
console.log(value());
console.log(value[0]);

これは便利なようで危険だ。実行時に TypeError: Cannot read property 'bar' of undefined のようなエラーが発生する可能性があるが、TypeScript はそれを検出できない。

any は型システムに「この変数のことは忘れてくれ」と伝えているようなものである。

unknown は安全な「何でも入る型」

unknown も任意の値を受け入れるが、そのまま使うことはできない。

const value: unknown = "hello";

// これらは全部エラーになる
// console.log(value.length);
// console.log(value());
// console.log(value[0]);

// 型を絞り込めば使える
if (typeof value === "string") {
  console.log(value.length);  // OK
}

unknown は「何が入っているかわからないから、確認してから使え」という意味だ。

any

何でも入る。何でもできる。型チェックなし。危険。

unknown

何でも入る。そのままでは何もできない。型チェックを強制。安全。

実際の使い分け

外部から入ってくるデータを扱うとき、unknown が活躍する。

// API レスポンスを受け取る
async function fetchUser(): Promise<unknown> {
  const res = await fetch("/api/user");
  return res.json();
}

// 使う側で型を検証する
const data = await fetchUser();
if (isUser(data)) {
  console.log(data.name);
}

function isUser(value: unknown): value is User {
  return (
    typeof value === "object" &&
    value !== null &&
    "name" in value &&
    typeof (value as User).name === "string"
  );
}

any を使うと型チェックをすり抜けてしまうが、unknown なら型ガードを書かざるを得ない。この「強制力」が安全性を担保する。

any を使ってもいい場面

とはいえ、any が完全に悪というわけではない。

移行期のコード

JavaScript から TypeScript への移行中、すべてに型を付けるのは現実的でないことがある。一時的に any を使い、徐々に型を付けていく戦略は有効。

型定義が複雑すぎる場合

サードパーティライブラリの型定義が不完全だったり、型パズルが複雑になりすぎる場合、any で逃げるのも選択肢。ただし // eslint-disable-next-line @typescript-eslint/no-explicit-any のようなコメントで意図を明示すべき。

unknown を使うべき場面

JSON.parse() の戻り値を扱うとき
外部 API のレスポンスを受け取るとき
ユーザー入力を処理するとき
catch ブロックでエラーを扱うとき

特に catch ブロックは注意が必要だ。TypeScript 4.4 以降、catch の引数はデフォルトで unknown になった。

try {
  throw new Error("something went wrong");
} catch (e) {
  // e は unknown 型
  if (e instanceof Error) {
    console.log(e.message);
  }
}

結論として、新規コードでは any より unknown を優先すべきだ。型の絞り込みを強制されることで、実行時エラーを未然に防げる。any は最後の手段として温存しておこう。