TypeScriptでGenericsを学習する

## はじめに
表題通りです。

## ソースコード
```ts:generics.ts
// スタックを定義するジェネリクスのクラス
class Stack<T> {
    private items: T[] = [];
  
    // スタックに要素を追加する
    push(item: T): void {
      this.items.push(item);
    }
  
    // スタックから要素を取り出す
    pop(): T | undefined {
      return this.items.pop();
    }
  
    // スタックが空かどうかを確認する
    isEmpty(): boolean {
      return this.items.length === 0;
    }
  
    // スタックの先頭要素を取得する（取り出さない）
    peek(): T | undefined {
      return this.items[this.items.length - 1];
    }
  }
  
  // 数値のスタックを作成する
  const numberStack = new Stack<number>();
  numberStack.push(1);
  numberStack.push(2);
  console.log(numberStack.pop()); // 2
  console.log(numberStack.peek()); // 1
  
  // 文字列のスタックを作成する
  const stringStack = new Stack<string>();
  stringStack.push("hello");
  stringStack.push("world");
  console.log(stringStack.pop()); // "world"
  console.log(stringStack.peek()); // "hello"
  
```

```shell:実行結果
~/develop/htmx$ ts-node generics.ts 
2
1
world
hello
```


```ts:generics_map.ts
class GenericMap<K, V> {
	private map: { [key: string]: V } = {};

	// キーと値をマップに追加する
	set(key: K, value: V): void {
		const stringKey = JSON.stringify(key);
		this.map[stringKey] = value;
	}

	// キーに対応する値を取得する
	get(key: K): V | undefined {
		const stringKey = JSON.stringify(key);
		return this.map[stringKey];
	}

	// キーを使って値を削除する
	delete(key: K): void {
		const stringKey = JSON.stringify(key);
		delete this.map[stringKey];
	}

	// マップがキーを持っているかどうかを確認する
	has(key: K): boolean {
		const stringKey = JSON.stringify(key);
		return stringKey in this.map;
	}
}

// 数値をキーにして文字列を値とするマップを作成する
const numberToStringMap = new GenericMap<number, string>();
numberToStringMap.set(1, "one");
numberToStringMap.set(2, "two");
console.log(numberToStringMap.get(1)); // "one"
console.log(numberToStringMap.has(2)); // true
numberToStringMap.delete(2);
console.log(numberToStringMap.has(2)); // false

// オブジェクトをキーにしてブール値を値とするマップを作成する
const objectToBooleanMap = new GenericMap<{ id: number }, boolean>();
const key = { id: 1 };
objectToBooleanMap.set(key, true);
console.log(objectToBooleanMap.get(key)); // true
console.log(objectToBooleanMap.has({ id: 1 })); // false (新しいオブジェクト参照のため)

```

```shell:実行結果
~/develop/htmx$ ts-node generics_map.ts 
one
true
false
true
true
```

```ts:generics_interface.ts
interface DataStorage<T> {
	addItem(item: T): void;
	removeItem(item: T): void;
	getItems(): T[];
}

class StringStorage implements DataStorage<string> {
	private items: string[] = [];

	addItem(item: string): void {
		this.items.push(item);
	}

	removeItem(item: string): void {
		this.items = this.items.filter((i) => i !== item);
	}

	getItems(): string[] {
		return [...this.items];
	}
}

class NumberStorage implements DataStorage<number> {
	private items: number[] = [];

	addItem(item: number): void {
		this.items.push(item);
	}

	removeItem(item: number): void {
		this.items = this.items.filter((i) => i !== item);
	}

	getItems(): number[] {
		return [...this.items];
	}
}

const stringStorage = new StringStorage();
stringStorage.addItem("hello");
stringStorage.addItem("world");
console.log(stringStorage.getItems()); // ["hello", "world"]

const numberStorage = new NumberStorage();
numberStorage.addItem(1);
numberStorage.addItem(2);
console.log(numberStorage.getItems()); // [1, 2]

```

```shell:実行結果
~/develop/htmx$ ts-node generics_interface.ts 
[ 'hello', 'world' ]
[ 1, 2 ]
```

:::note info
なかなか便利ですね！！Genericsは使い方色々なので応用できるように引き出しは多くもっとくといいですね！！
:::