404 Not Found

404 Not Found


nginx

TypeScript の配列とタプル

配列とタプルは、TypeScriptで最もよく使われる2つのコレクション型です。配列は「同じ型の値の集合」であり、タプルは「長さが固定されており、各要素の型が特定されている」配列の特殊な型です。

1. 配列の型

(1) 2つの注釈構文

TypeScript では、配列の型を記述する同等の方法が 2 つあります:

TYPESCRIPT
// Method 1:Type + square brackets(Recommendations,More intuitive)
let numbers: number[] = [1, 2, 3, 4, 5];
let names: string[] = ["Charlie", "Diana", "Eric"];

// Method 2:Generic Arrays(Commonly used in generic scenarios)
let scores: Array<number> = [90, 85, 95];
let items: Array<string> = ["a", "b", "c"];
📌 推奨事項: 日常の開発では、より簡潔な type[] という構文を使用してください。特定の複雑な型を扱う場合や、ジェネリック関数と併用する場合は、汎用構文 Array<T> の方が分かりやすくなります。

(2) 配列型の推論

TYPESCRIPT
let arr1 = [1, 2, 3];           // Inferred as number[]
let arr2 = ["a", "b", "c"];     // Inferred as string[]
let arr3 = [1, "hello", true];  // Inferred as (number | string | boolean)[]
let arr4 = [];                  // Inferred as any[](Danger!)
🔥 よくある間違い: 空の配列 []any[] と推論され、その後、異なる型の値を代入してもエラーにはなりません。厳格モードでは、明示的に let arr4: number[] = [] と指定することを推奨します。

(3) 多次元配列

TYPESCRIPT
let matrix: number[][] = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

// Accessing Elements
console.log(matrix[0][1]);  // 2

// Three-dimensional array
let cube: number[][][] = [[[1]]];

▶ 例:配列の基本操作

TYPESCRIPT
let fruits: string[] = ["Apple", "Banana", "Orange"];

// Add an element
fruits.push("Grapes");          // Add at the end
fruits.unshift("Strawberries");       // Add at the beginning

// Delete Element
let last = fruits.pop();      // Delete the end,Back "Grapes"
let first = fruits.shift();   // Delete the beginning,Back "Strawberries"

// Search
let index = fruits.indexOf("Banana");  // 0(The strawberries and grapes were removed.,The banana came in first)

// Iterate
fruits.forEach((fruit, i) => {
  console.log(`${i}: ${fruit}`);
});

出力:

TEXT
0: Banana
1: Orange

2. 読み取り専用配列

読み取り専用配列は変更できません。要素の追加、削除、変更は許可されていません:

(1) readonly 修飾子

TYPESCRIPT
let readonlyArr: readonly number[] = [1, 2, 3];

// readonlyArr[0] = 10;     // ❌ Read-only,Cannot be modified
// readonlyArr.push(4);     // ❌ Read-only,Cannot be added
// readonlyArr.length = 0;  // ❌ Read-only,The length cannot be changed

let normalArr: number[] = [1, 2, 3];
readonlyArr = normalArr;    // ✅ A regular array can be assigned to a read-only array
// normalArr = readonlyArr; // ❌ A read-only array cannot be assigned to a regular array.

(2) ReadonlyArray ジェネリック

TYPESCRIPT
let readonlyArr2: ReadonlyArray<string> = ["a", "b", "c"];
// and readonly string[] Equivalent
💡 目的: 読み取り専用の配列を関数の引数として使用することで、呼び出し元に「この関数はあなたの配列を変更しません」ということを明確に伝えることができます:

TYPESCRIPT
function printItems(items: readonly string[]) {
  items.forEach(item => console.log(item));
  // items.push("new");  // ❌ Compilation Error——The function is guaranteed not to be modified
}

let myItems = ["a", "b"];
printItems(myItems);  // Safety——myItems Will not be modified

3. タプル型

タプルは、「長さが固定されており、各要素の型が特定されている」配列であり、「名前付きの固定構造体」の軽量版と考えることができます。

(1) 基本的な構文

TYPESCRIPT
// Defining Tuples:[Type1, Type2, ...]
let user: [string, number] = ["Charlie", 20];

// Access by Index
console.log(user[0]);  // "Charlie"(string Type)
console.log(user[1]);  // 20(number Type)

// Assignments must match in type and length
// user = [20, "Charlie"];  // ❌ Type order does not match
// user = ["Charlie"];      // ❌ Not long enough
// user = ["Charlie", 20, true];  // ❌ Exceeds the length limit

(2) タプルと配列の違い

フィーチャー 配列 number[] タプル [string, number]
長さ 任意 固定
要素の種類 すべて同じ 位置によって異なる場合あり
アクセス すべての要素が同じ型である 各インデックスには特定の型がある
ユースケース 類似のデータセット 構造が固定された小規模なデータセット

(3) タプルの展開

TYPESCRIPT
let pair: [string, number] = ["Apple", 5];

let [fruit, count] = pair;
console.log(fruit);   // "Apple"
console.log(count);   // 5

// Including remaining elements
let record: [string, number, ...boolean[]] = ["Test", 100, true, false, true];
let [name, score, ...flags] = record;
console.log(name);    // "Test"
console.log(score);   // 100
console.log(flags);   // [true, false, true]

(4) 任意の要素

タプル内のオプション要素には、? を付けることができます:

TYPESCRIPT
let result: [string, number?] = ["Success"];

console.log(result[0]);  // "Success"
console.log(result[1]);  // undefined(Optional elements may be omitted.)
⚠️ Note: Optional elements can only appear at the end. [string?, number] is invalid—no required elements can follow an optional element.

(5) タグ付きタプル

TypeScript 4.0 ではタプルラベルが導入され、各位置の意味がより明確になりました:

TYPESCRIPT
let user: [name: string, age: number] = ["Charlie", 20];
let point: [x: number, y: number, z?: number] = [1.0, 2.5];

// Tags are only for document purposes,Does not affect the type——But the code's readability has improved significantly
function getRange(): [min: number, max: number] {
  return [0, 100];
}

let [min, max] = getRange();
console.log(`Scope:${min} - ${max}`);  // Scope:0 - 100

▶ 例:関数の戻り値としてのタプル

TYPESCRIPT
// Tuples are ideal for representing the return values of functions."Multiple values"
function divide(a: number, b: number): [quotient: number, remainder: number] {
  return [Math.floor(a / b), a % b];
}

let [quotient, remainder] = divide(17, 5);
console.log(`Quotient:${quotient},Remainder:${remainder}`);  // Quotient:3,Remainder:2

// A tuple represents a key-value pair
function entries(obj: Record<string, number>): [string, number][] {
  return Object.entries(obj) as [string, number][];
}

let scores = { Chinese Language: 90, Mathematics: 95, English: 88 };
for (let [subject, score] of entries(scores)) {
  console.log(`${subject}:${score}pts`);
}

出力:

TEXT
Quotient:3,Remainder:2
Chinese Language:90pts
Mathematics:95pts
English:88pts

4. 配列に対する高階演算

(1) ユニオン型配列とユニオン型の配列

TYPESCRIPT
// Union Type Arrays:Each element in the array can be number or string
let mixed: (number | string)[] = [1, "two", 3, "four"];

// Union Types for Arrays:Either... or number[],Either... or string[]
let uniform: number[] | string[] = [1, 2, 3];   // ✅
uniform = ["a", "b", "c"];                        // ✅
// uniform = [1, "two"];                          // ❌ Do not mix
🔥 よくある間違い: (number | string)[]number[] | string[] はまったく異なる意味を持っています!前者は「混合配列」を指し、後者は「純粋な数値配列または純粋な文字列配列」を指します。

(2) 配列メソッドの型安全性

TYPESCRIPT
let nums: number[] = [3, 1, 4, 1, 5];

// sort An explicit comparison function is required,Otherwise, sort by string
nums.sort((a, b) => a - b);     // ✅ Number Sorting:[1, 1, 3, 4, 5]

// map Automatic Inference of Return Types
let doubled = nums.map(n => n * 2);   // Inferred as number[]
let asStrings = nums.map(String);      // Inferred as string[]

// filter Automatically Infer Element Types
let big = nums.filter(n => n > 2);    // Inferred as number[]

(3) 配列のアンパックと型

TYPESCRIPT
let a: number[] = [1, 2];
let b: number[] = [3, 4];
let merged: number[] = [...a, ...b];  // [1, 2, 3, 4]

// Tuple Unpacking
let prefix: [string, number] = ["No.", 0];
let full: [string, number, ...number[]] = [...prefix, 1, 2, 3];
// full = ["No.", 0, 1, 2, 3]

5. 実際の開発における選択肢

(1) 配列を使うべき場面

(2) タプルを使うべき場合

(3) 読み取り専用配列を使用するタイミング

▶ 例:総合演習—学生の成績管理

TYPESCRIPT
// Represented as a tuple [Subject, Fractions]
type Score = [subject: string, score: number];

// Storing Multiple Grades in an Array
let scores: Score[] = [
  ["Chinese Language", 92],
  ["Mathematics", 88],
  ["English", 95],
  ["Physics", 78],
  ["Chemistry", 85]
];

// Calculate the average score
function average(scores: readonly Score[]): number {
  let total = scores.reduce((sum, [, score]) => sum + score, 0);
  return total / scores.length;
}

// Find the subject with the highest score
function topSubject(scores: readonly Score[]): Score {
  return scores.reduce((best, current) =>
    current[1] > best[1] ? current : best
  );
}

console.log("Average Score:" + average(scores).toFixed(1));
let [subject, score] = topSubject(scores);
console.log(`Subject with the Highest Score:${subject}(${score}pts)`);

出力:

TEXT
Average Score:87.6
Subject with the Highest Score:English(95pts)

❓ よくある質問

Q タプルと通常のオブジェクトの違いは何ですか?それぞれをいつ使用すべきですか?
A タプルはインデックス (tuple[0]) によってアクセスされるのに対し、オブジェクトはキー (obj.name) によってアクセスされます。タプルは、2~3個の要素からなる単純で固定された構造(座標やキーと値のペアなど)に適しています。要素が3つ以上ある場合や、意味論が複雑な場合は、オブジェクトやインターフェースを使用してください。なぜなら、user.nameuser[0]よりもはるかに読みやすいからです。
Q (number | string)[] と number[] | string[] の違いは具体的に何ですか?
A (number | string)[] は、「各要素が数値または文字列のいずれか」である配列です。つまり、[1, "a", 2] のように、両方の型が混在することが許されます。number[] | string[]は、「配列全体がすべて数値か、すべて文字列のいずれかである」という配列です。型が混在することは許可されていないため、[1, "a"]は無効です。後者は2つの配列型の和集合であり、ユニオン型の配列ではありません。
Q タプルのpush/pop操作で型チェックが行われないのはなぜですか?
A これはTypeScriptにおける既知の設計上の欠陥です。タプル内での範囲外の要素へのアクセス(例:tuple[100])はエラーを発生させますが、push/popメソッドは、厳格モードであっても型チェックされずに実行されてしまいます。変更を完全に防ぐためには、readonlyタプル(readonly [string, number])を使用することを推奨します。

📖 まとめ

📝 練習問題

  1. 基本問題(難易度 ⭐):5つのプログラミング言語の名前を格納するための配列 string[] を作成し、forEach を使ってその要素を順に読み込み、出力してください。次に、読み取り専用バージョン readonly string[] を作成し、それを変更してみて、表示されるエラーメッセージを確認してください。
  2. 上級問題(難易度 ⭐⭐):タプル内の2つの要素の位置と型を入れ替える関数 swap(tuple: [string, number]): [number, string] を定義してください。例えば、swap(["hello", 42])[42, "hello"] を返します。
  3. チャレンジ問題(難易度 ⭐⭐⭐):CSVテキストファイルをタプルに解析する関数 parseCSV(lines: string[]): [header: string[], ...rows: string[][]] を実装してください。このファイルでは、1行目がヘッダー、残りの行がデータとなります。戻り値は、残りの要素を含むタグ付きタプルである必要があります。
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%