[TypeScript]ジェネリッククラス

class Box<T> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  getValue(): T {
    return this.value;
  }

  setValue(newValue: T): void {
    this.value = newValue;
  }
}

// 使用例
const numberBox = new Box<number>(10);
console.log(numberBox.getValue()); // 10

const stringBox = new Box<string>("Hello");
console.log(stringBox.getValue()); // "Hello"

 
複数の型パラメータ

class Pair<T, U> {
  constructor(private first: T, private second: U) {}

  getFirst(): T {
    return this.first;
  }

  getSecond(): U {
    return this.second;
  }
}

// 使用例
const pair1 = new Pair<number, string>(1, "One");
console.log(pair1.getFirst()); // 1
console.log(pair1.getSecond()); // "One"

const pair2 = new Pair<boolean, string>(true, "True");
console.log(pair2.getFirst()); // true
console.log(pair2.getSecond()); // "True"

 
ジェネリック型Tに特定の型を継承させて型の制約を設ける

class Calculator<T extends number> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  add(num: T): number {
    return this.value + num;
  }
}

// 使用例
const calc = new Calculator(10);
console.log(calc.add(5)); // 15

// const invalidCalc = new Calculator("Hello"); // エラー: stringはnumberを継承していない

 
クラスとインターフェースの組み合わせ

interface Identifiable {
  id: number;
}

class Repository<T extends Identifiable> {
  private items: T[] = [];

  add(item: T): void {
    this.items.push(item);
  }

  findById(id: number): T | undefined {
    return this.items.find(item => item.id === id);
  }
}

// 使用例
interface User {
  id: number;
  name: string;
}

const userRepo = new Repository<User>();
userRepo.add({ id: 1, name: "Taro" });
userRepo.add({ id: 2, name: "Jiro" });

console.log(userRepo.findById(1)); // { id: 1, name: "Taro" }
console.log(userRepo.findById(3)); // undefined

 
デフォルト型を指定

class DefaultBox<T = string> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  getValue(): T {
    return this.value;
  }
}

// 使用例
const defaultBox = new DefaultBox("Hello"); // string型を推論
console.log(defaultBox.getValue()); // "Hello"

const numberBox = new DefaultBox<number>(100); // 明示的にnumber型を指定
console.log(numberBox.getValue()); // 100

 
コンストラクタで型推論

class DataStorage<T = number>{
    private items:T[] = [];
    constructor(initItems?:T[]){
        if(initItems){
            this.items.push(...initItems);
        }
    }
}
let stringStorage = new DataStorage(["A","B"]);

 
ジェネリッククラスの継承

class DataStorage<T>{
    private items:T[] = [];
}
class DataStorageSub extends DataStorage<string>{
    logAllItems():void{
        console.log([...this.items]);
    }
}
class DataStorageSub<T> extends DataStorage<T>{
    logAllItems():void{
        console.log([...this.items]);
    }
    getLastValue():T{
        return this.items[this.items.length-1];
    }
}