TypeScriptにおいて、配列の初期化はプログラミングの基本でありながら、型の安全性を確保する上で非常に重要な工程です。
適切に初期化を行わないと、実行時のエラーや意図しない型の混入を招く可能性があります。
本記事では、TypeScriptにおける配列初期化の基本から、型安全性を高めるための高度なパターンまで詳しく解説します。
最新の開発環境においても通用する、効率的でミスのない実装方法を身につけていきましょう。
配列初期化の基本:リテラルによる宣言
TypeScriptで最も一般的に使用される配列の初期化方法は、配列リテラルを用いた宣言です。
この方法では、角括弧 [] を使用して配列を定義します。
変数を宣言する際に型注釈を添えることで、その配列がどのような要素を持つべきかを明示できます。
型注釈を用いた初期化
最もシンプルで推奨される方法は、変数名の後ろに型を指定する形式です。
// 数値型の配列を初期化する
const numbers: number[] = [1, 2, 3, 4, 5];
// 文字列型の配列を初期化する
const fruits: string[] = ["apple", "banana", "orange"];
このように記述することで、指定した型以外の要素が追加されるのをコンパイル時に防ぐことができます。
ジェネリック型を用いた初期化
もう一つの記述方法として、Array<型> というジェネリック構文を使用する方法があります。
// ジェネリック構文による初期化
const scores: Array<number> = [90, 85, 70];
この書き方は number[] と機能的に同じですが、ReactなどのJSXを使用する環境では、タグと混同される可能性があるため注意が必要です。
基本的には T[] 形式を使用し、複雑な型を扱う場合に Array<T> を検討するのが一般的です。
Arrayコンストラクタによる初期化と注意点
特定の要素数で配列を確保したい場合、new Array() コンストラクタを使用することがあります。
しかし、この方法にはJavaScript特有の挙動が含まれるため、注意が必要です。
要素数を指定した初期化
あらかじめサイズが決まっている配列を作成する場合、以下のように記述します。
// 5つの要素を持つ空の配列を作成する
const buffer = new Array<number>(5);
このコードは、メモリ上に5つ分の領域を確保しますが、中身は empty (空) 状態であることに注意してください。
この状態で map メソッドなどを使用しても、要素が存在しないためループ処理が行われません。
空の配列の初期化と型推論
空の配列 [] で初期化する際に型を指定しないと、TypeScriptは any[] として推論しようとします。
// 型指定がない場合
const items = []; // any[] と見なされるリスクがある
any[] は型安全性を失わせる原因となるため、空の配列で初期化する場合は必ず型を明示するようにしましょう。
規定値で埋められた配列の作成パターン
初期化と同時に、すべての要素を特定の値で埋めたいケースは頻繁に発生します。
ここでは、代表的な3つの手法を解説します。
fillメソッドを使用する方法
Array(n).fill(value) を使用すると、指定した値で配列を埋めることができます。
// すべての要素を 0 で初期化する
const zeros: number[] = new Array(5).fill(0);
[0, 0, 0, 0, 0]
ただし、オブジェクトを fill に渡す場合は注意が必要です。
すべての要素が同じオブジェクトの参照を共有してしまうため、一つの要素を変更するとすべてが変わってしまいます。
Array.fromを使用する方法
参照の共有問題を回避しつつ、動的に値を生成したい場合は Array.from() が最適です。
// 各要素に新しいオブジェクトを割り当てる
const users = Array.from({ length: 3 }, () => ({ name: "unknown" }));
users[0].name = "Alice";
[ { name: "Alice" }, { name: "unknown" }, { name: "unknown" } ]
この方法であれば、各要素は個別のメモリ領域を持つ独立したオブジェクトとして初期化されます。
連番による初期化
開発において、0から始まる連番の配列を作成したい場合も Array.from が便利です。
// 0から4までの連番配列を作成
const range: number[] = Array.from({ length: 5 }, (_, i) => i);
[0, 1, 2, 3, 4]
第2引数のコールバック関数を活用することで、インデックスに基づいた複雑な初期化も柔軟に行えます。
型安全性を極めるための高度な初期化
TypeScriptの真価を発揮するために、より厳格な配列の扱いについても確認しておきましょう。
readonlyによる読み取り専用配列
初期化後に要素を変更させたくない場合は、readonly 修飾子を使用します。
// 読み取り専用の配列
const config: readonly string[] = ["API_URL", "TIMEOUT"];
// エラー:要素の変更は許可されない
// config[0] = "NEW_URL";
readonly を付与することで、意図しない破壊的なメソッド (pushやpopなど) の呼び出しをコンパイルエラーとして検知できます。
タプル型による厳密な初期化
配列の要素数と各位置の型が固定されている場合は、タプル型を使用します。
// 要素数2、[数値, 文字列] の順序を強制する
const response: [number, string] = [200, "OK"];
タプル型を使うことで、配列を単なるデータの集まりではなく、構造化されたデータとして安全に扱うことが可能になります。
as constによるリテラル型としての初期化
定数として配列を定義する場合、as const (constアサーション) を活用するのがベストプラクティスです。
// リテラル型として固定する
const modes = ["dark", "light"] as const;
// 型は "dark" | "light" の配列(読み取り専用)になる
type Mode = typeof modes[number];
これにより、配列の内容を型情報として抽出でき、他のコードとの整合性を保ちやすくなります。
多次元配列の初期化
2次元配列 (行列) などの初期化は、記述が複雑になりやすいため整理が必要です。
以下は、3×3のグリッドを 0 で初期化する例です。
// 2次元配列の初期化
const matrix: number[][] = Array.from({ length: 3 }, () => Array(3).fill(0));
このように、外側の Array.from の中で内側の配列を生成することで、各行が独立した参照を持つようになります。
もし fill(new Array(3).fill(0)) と記述してしまうと、すべての行が同一の配列を参照してしまうため注意してください。
パフォーマンスと初期化のトレードオフ
2026年現在のモダンなJavaScriptエンジンにおいても、配列の初期化方法はパフォーマンスに影響を与えます。
大量のデータを扱う場合、動的に push を繰り返すよりも、あらかじめ new Array(size) で領域を確保してから値を代入する方が高速な場合があります。
ただし、これは数万要素を超えるようなケースでの話であり、通常は可読性の高いリテラル表記や Array.from を優先すべきです。
まずは「正しく型が定義されていること」を最優先にし、必要に応じて最適化を検討しましょう。
まとめ
TypeScriptにおける配列の初期化は、単にデータを作成するだけでなく、プログラムの堅牢性を決定づける重要な作業です。
基本となるリテラル表記に加え、用途に応じて Array.from や readonly、as const を使い分けることが求められます。
特に、空の配列に対する型明示や、オブジェクトを初期値にする際の参照共有問題には十分に注意してください。
型安全な初期化パターンを徹底することで、バグの少ない、メンテナンス性に優れたコードを実現できるでしょう。
本記事で紹介した各パターンを、ぜひ日々の開発に役立ててください。
