TypeScriptにおいて、変数を宣言する際にvarを使用することは、現代の開発シーンでは推奨されていません。
2026年現在、TypeScriptのエコシステムはより堅牢で予測可能なコードを記述する方向に進化しており、varの使用は技術的な負債を生む要因となります。
かつてのJavaScriptではvarが唯一の変数宣言手段でしたが、ECMAScript 2015(ES6)の登場以降、その役割はletとconstに完全に置き換わりました。
本記事では、なぜTypeScriptでvarを使ってはいけないのか、その具体的な理由と、安全なコードを書くための代替手段について深く掘り下げていきます。
プログラムの挙動を安定させ、バグの混入を防ぐための基礎知識として、スコープや巻き上げといった重要な概念を整理しましょう。
varが非推奨とされる根本的な理由
varが使われない最大の理由は、その挙動が現代のプログラミング言語の直感から大きく外れている点にあります。
特に「スコープ」と「巻き上げ」という2つの特性が、大規模な開発において深刻なバグを引き起こす原因となってきました。
スコープの範囲が広すぎる問題
varで宣言された変数は、「関数スコープ」を持ちます。
これは、if文やfor文などのブロック({})の中で変数を宣言しても、その外側から変数にアクセスできてしまうことを意味します。
具体的なコード例で、その不自然な挙動を確認してみましょう。
function scopeTest() {
if (true) {
var x = "Hello TypeScript"; // ブロック内で宣言
}
console.log(x); // 本来ならエラーになるべき場所だがアクセスできてしまう
}
scopeTest();
Hello TypeScript
このように、ブロック外から変数が見えてしまうことは、変数の汚染を招き、予期せぬ場所で値が書き換わるリスクを高めます。
特に複雑なループ処理や条件分岐が重なる関数内では、意図しない変数の共有が発生し、デバッグが困難なバグを生み出すことになります。
巻き上げ(ホイスティング)による予期せぬ挙動
varには、宣言がスコープの先頭に引き上げられる「巻き上げ(ホイスティング)」という性質があります。
これにより、変数を宣言する前のコード行でその変数を使用しても、エラーにならずにundefinedが返されます。
function hoistingTest() {
console.log(message); // 宣言前なのにアクセス可能
var message = "初期化されたメッセージ";
}
hoistingTest();
undefined
通常、変数は宣言されてから使われるべきですが、varはこの順序性を無視することを許容してしまいます。
この挙動はコードの可読性を著しく低下させ、実行時の論理エラーを誘発する一因となります。
同一名称での再宣言が許可されてしまうリスク
varを使用すると、同じスコープ内で同じ名前の変数を何度でも宣言し直すことができてしまいます。
これは、大規模な開発チームにおいて、他の開発者がすでに定義した変数を誤って上書きしてしまう危険性を孕んでいます。
var userName = "Alice";
// ...数百行のコード...
var userName = "Bob"; // エラーにならずに再宣言できてしまう
console.log(userName);
Bob
TypeScriptの静的解析を用いても、varを使っている限り、このような二重定義のミスを完全に防ぐことは難しくなります。
let と const を使い分けるメリット
現代のTypeScript開発において、varの代わりに利用すべきなのがletとconstです。
これらはvarが抱えていた多くの問題を解決し、開発者に安全なコーディング環境を提供します。
ブロックスコープによる安全性の向上
letとconstは、「ブロックスコープ」を採用しています。
これにより、変数の有効範囲が{}の中に限定され、外部からの不要な干渉を完全に遮断することができます。
function blockScopeExample() {
if (true) {
let blockScopedVar = "Secret";
console.log(blockScopedVar); // ブロック内でのみ有効
}
// console.log(blockScopedVar); // ここでアクセスしようとするとコンパイルエラーになる
}
変数の影響範囲を最小限に留めることは、「副作用の少ないコード」を書くための基本原則です。
スコープが適切に制御されていることで、コードの可読性が向上し、修正時の影響範囲の特定も容易になります。
一時的死角(TDZ)による安全性の確保
letやconstにも巻き上げ自体は存在しますが、宣言前にアクセスしようとするとReferenceErrorを発生させる仕組みがあります。
これを「一時的死角(Temporal Dead Zone)」と呼びます。
function tdzExample() {
// console.log(tempValue); // 実行前にTypeScriptがエラーを出力する
let tempValue = "Value";
}
「変数は宣言してから使う」という当たり前のルールを言語仕様として強制できるため、論理的なミスを未然に防ぐことが可能です。
イミュータビリティ(不変性)の意識
constを使用することで、一度代入した値を変更できない「再代入不可」の定数として定義できます。
現代のプログラミングでは、状態の変化を最小限に抑える「イミュータビリティ(不変性)」が重視されています。
すべての変数をデフォルトでconstとして定義し、どうしても再代入が必要な場合のみletを使用するというスタイルが、2026年現在のベストプラクティスです。
const apiKey = "xyz-123";
// apiKey = "abc-456"; // TypeScriptがエラーを出し、不正な変更を阻止する
let counter = 0;
counter += 1; // 変更が必要な場合のみ let を使う
constを多用することで、コードを読み手に対して「この変数の値は後で変わることがない」という強いメッセージを伝えることができます。
比較表: var / let / const
それぞれの違いを理解しやすくするために、主要な特性を表にまとめました。
| 機能・特性 | var | let | const |
|---|---|---|---|
| スコープ | 関数スコープ | ブロックスコープ | ブロックスコープ |
| 再宣言 | 可能 | 不可能 | 不可能 |
| 再代入 | 可能 | 可能 | 不可能 |
| 巻き上げの挙動 | undefinedで初期化 | エラー(TDZ) | エラー(TDZ) |
| 推奨度 | 非推奨(Legacy) | 推奨 | 最も推奨 |
この表からわかる通り、varには現代的な利点は一つもありません。
TypeScriptの強力な型チェックを最大限に活かすためにも、letおよびconstの利用を徹底すべきです。
TypeScriptにおける実践的な管理方法
プロジェクト全体でvarの使用を禁止し、コードの品質を一貫させるためには、ツールの活用が不可欠です。
ESLintによる制限設定
TypeScriptプロジェクトでは、ESLintを導入して no-var ルールを有効化することが一般的です。
これにより、誤ってvarを記述した場合、エディタ上で即座に警告が表示され、ビルドを阻止することができます。
// .eslintrc.json の設定例
{
"rules": {
"no-var": "error",
"prefer-const": "error"
}
}
prefer-const ルールも併用することで、再代入されていない let 変数を const に変更するよう促されるため、より洗練されたコードに近づきます。
既存コードのリファクタリング
もし古いプロジェクトでvarが残っている場合は、段階的にリファクタリングを行うことが推奨されます。
単純に var を let に書き換えるだけでも、スコープが適切に制限されるため、潜在的なバグが表面化して修正のきっかけになります。
TypeScriptのコンパイラオプションで strict: true を設定していれば、スコープ外からの不正なアクセスをコンパイルエラーとして即座に検出できるため、安全に移行作業を進められます。
リファクタリング時の注意点
varをletに置き換える際、まれに巻き上げの性質に依存したトリッキーなコードが書かれていることがあります。
その場合は、変数の宣言位置を使用する直前に移動させるなど、コードの構造自体を見直す良い機会となります。
安全なコードを書くためには、言語の機能を正しく理解し、ベストプラクティスに従った設計を心がけることが大切です。
まとめ
TypeScriptでvarを使わない理由は、単に古いからではなく、「コードの安全性と予測可能性を著しく損なうから」です。
関数スコープや巻き上げ、再宣言の許可といったvarの特性は、現代の開発規模においてはリスクでしかありません。
ブロックスコープを持つletと、不変性を担保するconstを使い分けることで、バグの少ない、メンテナンス性の高いコードを実現できます。
特にconstを第一選択肢とし、どうしても必要な場合のみletを使うという習慣を徹底しましょう。
ツールによる強制(ESLint)も組み合わせることで、チーム全体のコード品質を高い水準で維持することが可能になります。
TypeScriptの恩恵を最大限に享受するために、今日からvarとは決別し、よりモダンで安全なプログラミングを実践していきましょう。
