配列は多くのプログラミング言語において基本的なデータ構造で、数値や文字列など、同じ型の要素の集まりを格納するために用いられます。
TypeScriptで配列を作成する方法の1つに、配列リテラルという記法があります。括弧[]を使い、要素をカンマで区切ると配列を表現できます。
let numbers: number[] = [1, 2, 3, 4, 5];
let words: string[] = ['hello', 'world'];
let arr: (number | string)[] = [1, 'a'];
上の例では、配列の要素の型に[]を付けて、型を指定しています。これは型注釈と呼ばれ、変数や定数が持つ値の型を示すために使用されます。
配列は、以下のように宣言することも可能です。
let numbers: Array<number> = [1, 2, 3, 4, 5];
let words: Array<string> = ['hello', 'world'];
let arr: Array<string | number> = [1, 'a'];
配列ができたら、その要素にアクセスするには、0から始まる配列内の要素の位置であるインデックスを使用します。
console.log(numbers[0]); // 1
console.log(words[1]); // 'world'
TypeScriptには、配列を操作するために使用できる組み込みの配列メソッドが多数用意されています。よく使われるものには以下のようなものがあります。
例えば、数値の配列の末尾に要素を追加したい場合、pushメソッドを使用します。
let numbers: number[] = [1, 2, 3, 4, 5];
numbers.push(6);
console.log(numbers); // [1,2,3,4,5,6]
数値の配列の末尾から要素を取り出したい場合、popメソッドを使用します。
let numbers: number[] = [1, 2, 3];
let lastNumber = numbers.pop();
console.log(numbers); // [1, 2]
console.log(lastNumber); // 3
数値の配列の先頭にから要素を取り出したい場合、shiftメソッドを使用します。
let fruits = ["apple", "banana", "cherry"];
let first = fruits.shift();
console.log(first); // "apple"
console.log(fruits); // ["banana", "cherry"]
数値の配列の先頭に要素を追加したい場合、unshiftメソッドを使用します。
let fruits = ["apple", "banana", "cherry"];
let newLength = fruits.unshift("orange", "peach");
console.log(newLength); // 5
console.log(fruits); // ["orange", "peach", "apple", "banana", "cherry"]
元の配列の一部をコピーし、新しい配列を作成したい場合、sliceメソッドを使用します。
let numbers: number[] = [1, 2, 3, 4, 5];
let subNumbers = numbers.slice(1, 3);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(subNumbers); // [2, 3]
削除された要素を含む配列を返し、元の配列を変更したい場合、splice()メソッドを使用します。
let fruits = ["apple", "banana", "cherry"];
let removed = fruits.splice(1, 1, "orange", "peach");
console.log(removed); // ["banana"]
console.log(fruits); // ["apple", "orange", "peach", "cherry"]
TypeScriptのsort()メソッドは配列の組み込み関数で、配列の要素をその場でソートして、ソート後の配列を返します。デフォルトのソート順は、要素を文字列に変換し、UTF-16コード単位の値の並びを比較することで構築されています。
sort()の引数としてcompare関数を渡して、ソート順を指定することもできます。compare関数は、引数に応じて負の値、ゼロの値、正の値を返す必要があります。
let fruits = ["apple", "banana", "cherry"];
fruits.sort();
console.log(fruits); // ["apple", "banana", "cherry"]
let numbers = [40, 100, 1, 5, 25, 10];
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 5, 10, 25, 40, 100]
TypeScriptのforEach()メソッドは配列の組み込み関数で、配列の各要素に対して与えられた関数を一度実行します。元の配列には手を加えず、新しい値も返しません。forEach()メソッドは引数としてコールバック関数を取り、以下の引数を受け取ることができます。
let fruits = ["apple", "banana", "cherry"];
fruits.forEach((fruit, index, array) => console.log(fruit, index));
// apple 0
// banana 1
// cherry 2
コールバック関数を元の配列の各要素に適用して、新しい配列を作成したい場合、mapメソッドを使用します。配列の各要素を2倍してみます。
let numbers: number[] = [1, 2, 3];
let doubleNumbers = numbers.map(num => num * 2);
console.log(numbers); // [1, 2, 3]
console.log(doubleNumbers); // [2, 4, 6]
コールバック関数を元の配列の各要素に適用して、trueを返すすべての要素で新しい配列を作成したい場合、filterメソッドを使います。コールバック関数が真を返した場合は、その要素が新しい配列に含まれ、そうでない場合は除外されます。
コールバック関数は3つの引数を入力として受け取ることができます。
let numbers = [1, 2, 3, 4, 5, 6];
let evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(evenNumbers); // [2, 4, 6]
TypeScriptでは、暗黙的に型付けが行われるので、以下のような処理はエラーが表示されます。
let numbers = [1, 2, 3, 4, 5];
numbers.push(true); // error
TypeScriptで配列の各要素にアクセスするには、いくつかの方法があります。
forループを使うと、配列を繰り返し処理し、各要素にインデックスでアクセスすることができます。
let numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}
上の例では1, 2, 3, 4, 5の数字が出力されます。
ネストされたforループも見てみましょう。
let nestedNumbers = [[1, 2], [3, 4], [5, 6]];
for (let i = 0; i < nestedNumbers.length; i++) {
for (let j = 0; j < nestedNumbers[i].length; j++) {
console.log(nestedNumbers[i][j]);
}
}
for-of文を使っても、配列の各要素にアクセスすることができます。
let numbers = [1, 2, 3, 4, 5];
for (let num of numbers) {
console.log(num);
}
forEach()メソッドで、配列の各要素にコールバック関数を適用することもできます。
let numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => console.log(num));
スプレッド演算子(...)は、TypeScriptとJavaScriptの機能で、反復可能なもの(配列や文字列など)を個々の要素に展開することができます。
既存の配列の要素で新しい配列を作成する場合は、以下のように記述します。
let originalNumbers = [1, 2, 3];
let newNumbers = [...originalNumbers, 4, 5];
console.log(newNumbers); // [1, 2, 3, 4, 5]
ある配列の要素を別の配列の末尾に追加する場合、以下のように記述します。
let firstNumbers = [1, 2, 3];
let secondNumbers = [4, 5, 6];
let combinedNumbers = [...firstNumbers, ...secondNumbers];
console.log(combinedNumbers); // [1, 2, 3, 4, 5, 6]
配列の要素を個別の引数として関数に渡すこともできます。
let numbers = [1, 2, 3];
console.log(Math.max(...numbers)); // 3
2つ以上のオブジェクトを結合することもできます。
let obj1 = { a: 1, b: 2 };
let obj2 = { c: 3, d: 4 };
let obj3 = { ...obj1, ...obj2 };
console.log(obj3); // { a: 1, b: 2, c: 3, d: 4 }
注目すべきは、スプレッド演算子が文字列、集合、マップなど、あらゆる反復可能なデータ型でも同様に機能することです。
let str = "Hello";
let chars = [...str];
console.log(chars); // ['H','e','l','l','o']
スプレッド演算子を使用した場合、元のオブジェクトや配列は変更されない点に注意しましょう。
TypeScriptでは、readonlyキーワードを使って配列を読み取り専用にすることができます。これは、配列の作成後にその要素を変更できないようにすることを意味します。これは、配列に格納されたデータが変更されないことを保証したい場合に便利になります。
let numbers: readonly number[] = [1, 2, 3, 4, 5];
numbers[0] = 6; // エラー
この例では、readonlyキーワードを使用して、numbers配列を読み取り専用にし、その要素を変更できないようにしています。この配列の要素を変更しようとすると、コンパイル時エラーが発生します。
ReadonlyArray
let numbers: ReadonlyArray<number> = [1, 2, 3, 4, 5];
Note: 配列については、CS基礎/中級/配列で詳しく学習できます。