【TypeScript初学者向け】Generics型におけるArray<T> についての豆知識

# はじめに
OREILLYの「初めてのTypeScript」をパラパラとめくっていて、ジェネリクス型の章でちょっとおもしろい豆知識があったので紹介します:point_up:

TypeScript初学者には是非おススメしたい書籍なので、これから始めてみようという方はコレ一択なやつです。

https://amzn.to/4cHAesO

![image_6487327 (4).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492127/d2278b47-d246-076f-79d5-9d3bd2767775.jpeg)


# 概要
TypeScript の `Array<T>` インターフェースは、配列操作のための様々なメソッドを定義しています。ここでは`pop()` と `push()` メソッドについての使い方とTypeScriptでの挙動を解説してきます。

まず下記をリーディングしてみましょう。

```typescript
interface Array<T> {
    pop(): T | undefined;
    push(...items: T[]): number;
}
```
さあ、このコードの意味が理解できましたでしょうか？？
それでは解説していきます:writing_hand:

## 型の詳細とメソッド解説

### pop()

配列の最後の要素を削除し、その要素を返します。

- 戻り値: `T | undefined`
  - `T`: 削除された最後の要素
  - `undefined`: 配列が空の場合

### push()

一つ以上の要素を配列の末尾に追加します。

- 引数: `...items: T[]` (可変長引数)
- 戻り値: `number` (新しい配列の長さ)

### 上記を踏まえて簡単なコード例
```typescript
// 数値の配列
let numbers: Array<number> = [1, 2, 3];

// pop の使用
let lastNumber = numbers.pop(); // lastNumber は 3 または undefined

// push の使用
let newLength = numbers.push(4, 5); // newLength は 4 (新しい配列の長さ)

// 文字列の配列
let fruits: Array<string> = ["apple", "banana"];

// pop の使用
let lastFruit = fruits.pop(); // lastFruit は "banana" または undefined

// push の使用
let newFruitCount = fruits.push("orange", "grape"); // newFruitCount は 3
```

## 実用的な例

### 例1: タスク管理アプリケーション

```typescript
interface Task {
    id: number;
    description: string;
    completed: boolean;
}

class TaskManager {
    private tasks: Array<Task> = [];

    addTask(description: string): number {
        const newTask: Task = {
            id: Date.now(),
            description,
            completed: false
        };
        return this.tasks.push(newTask);
    }

    completeLastTask(): Task | undefined {
        const lastTask = this.tasks.pop();
        if (lastTask) {
            lastTask.completed = true;
            this.tasks.push(lastTask);
        }
        return lastTask;
    }

    getTasks(): Array<Task> {
        return this.tasks;
    }
}

// 使用例
const manager = new TaskManager();
console.log(manager.addTask("レポートを書く")); // 1
console.log(manager.addTask("買い物に行く")); // 2
console.log(manager.getTasks()); // 2つのタスクが表示される
console.log(manager.completeLastTask()); // 最後のタスク（買い物に行く）が完了としてマークされる
console.log(manager.getTasks()); // 2つのタスク（最後のタスクが完了状態）が表示される
```

### 例2: 履歴管理システム

```typescript
class BrowserHistory<T> {
    private history: Array<T> = [];
    private maxSize: number;

    constructor(maxSize: number = 10) {
        this.maxSize = maxSize;
    }

// 新しい項目を履歴に追加
    addToHistory(item: T): void {
        if (this.history.length >= this.maxSize) {
            this.history.shift(); // 最も古い項目を削除
        }
        this.history.push(item);
    }

// 最新の履歴項目の確認
    goBack(): T | undefined {
        return this.history.pop();
    }
    
// 現在の履歴全体の確認
    getCurrentHistory(): Array<T> {
        return this.history;
    }
}

// 使用例
// ここでTがstringに確定するからstringの配列操作のみが可能になる
const urlHistory = new BrowserHistory<string>(5); 

urlHistory.addToHistory("https://example.com");
urlHistory.addToHistory("https://example.com/about");
urlHistory.addToHistory("https://example.com/contact");

console.log(urlHistory.getCurrentHistory()); 
// ["https://example.com", "https://example.com/about", "https://example.com/contact"]

console.log(urlHistory.goBack()); // "https://example.com/contact"
console.log(urlHistory.getCurrentHistory()); 
// ["https://example.com", "https://example.com/about"]
```

これらの使用箇所でArrayインターフェースは以下のように機能しています

**型安全性の確保: T 型の要素のみを配列に追加できるようにします。**
**メソッドの型定義: push, pop などのメソッドの戻り値の型を正確に定義します。**


# まとめ
組み込みのArrayメソッドは、TypeScriptではジェネリクス型のインターフェースとして定義されているので、覚えておきましょう！