TSの型システムを自動販売機を使って説明してみる

みなさん、TypeScriptで型を定義していますか？

そもそも型システムってよく聞くけど、なんだかわからないという人、プログラミング学習の初心者には多いのではないかと思います。私もそうでした。

今日はそんな方に向けて、TypeScriptの型システムをゆるめに解説していきます。

# 型システムってなに？

さて、型システムって何でしょうか。

> 型システムは、プログラミングの中で使われるデータや値に「型」という特徴をつけて、それをルールに沿って管理する仕組みのことです。型があることで、変数や関数が扱うデータの種類が決まり、間違った使い方を防ぐことができます。(wikipediaより)

wikipediaにはこう書いてありますが、正直これだけではちょっとわかりにくいですよね。もっと簡単に考えてみましょう。

たとえば、お金を考えてみてください。100円や500円といった硬貨がありますよね。それぞれの硬貨には「種類」があって、それを型に例えることができます。型を定義することで、「このお金は100円硬貨です」「このお金は500円硬貨です」と決めることができます。これが型システムの役割のひとつで、誤った種類のお金を使うのを防ぐことができます。

# 自動販売機で考えてみる
自動販売機を例に考えてみましょう。自動販売機は、皆さんがよく使う機械で、お金を入れて飲み物を買いますよね。この仕組みをコードで書いてみると、型システムがどのように使われるかがよくわかります。

以下は、自動販売機をTypeScriptで書いたコードです。

```TypeScript
// 商品の種類を定義
type Beverage = "coffee" | "tea" | "soda";

// 100円硬貨の型を定義
interface HundredYenCoin {
  type: "hundred";
  value: 100;
}

// 500円硬貨の型を定義
interface FiveHundredYenCoin {
  type: "fiveHundred";
  value: 500;
}

// 硬貨の種類を定義
type Coin = HundredYenCoin | FiveHundredYenCoin;

// 在庫状態を表すインターフェース
interface Stock {
  coffee: number;
  tea: number;
  soda: number;
}

// 自動販売機の状態を表すインターフェース
interface VendingMachine {
  stock: Stock;
  balance: number;
}

// 購入結果を表すユニオン型
type PurchaseResult =
  | { success: true; item: Beverage; change: number }
  | { success: false; reason: "insufficient_funds" | "out_of_stock" };

// 自動販売機クラス
class BeverageVendingMachine implements VendingMachine {
  stock: Stock = {
    coffee: 5,
    tea: 5,
    soda: 5,
  };
  balance: number = 0;

  // 硬貨投入メソッド
  insertCoin(coin: Coin): void {
    this.balance += coin.value;
    console.log(`${coin.value}円硬貨を投入しました。現在の残高は${this.balance}円です。`);
  }

  // 商品購入メソッド
  purchase(item: Beverage): PurchaseResult {
    const price = 150; // すべての飲み物が150円と仮定

    if (this.stock[item] === 0) {
      return { success: false, reason: "out_of_stock" };
    }

    if (this.balance < price) {
      return { success: false, reason: "insufficient_funds" };
    }

    this.stock[item]--;
    const change = this.balance - price;
    this.balance = 0;

    return {
      success: true,
      item: item,
      change: change,
    };
  }
}

// 使用例
const machine = new BeverageVendingMachine();

const hundredYenCoin: HundredYenCoin = { type: "hundred", value: 100 };
const fiveHundredYenCoin: FiveHundredYenCoin = { type: "fiveHundred", value: 500 };

machine.insertCoin(fiveHundredYenCoin);
const result = machine.purchase("coffee");

if (result.success) {
  console.log(`購入成功: ${result.item}, おつり: ${result.change}円`);
} else {
  console.log(`購入失敗: ${result.reason}`);
}
```

まず、商品の種類について見てみましょう。このコードでは「コーヒー」「紅茶」「ソーダ」を用意しています。それぞれの商品は「Beverage」という型に定義されていて、この型に含まれない商品を買おうとすると、エラーが出るようになっています。これによって、存在しない商品を間違えて入力することが防げます。

次に、貨幣の種類についてです。この自動販売機は100円硬貨と500円硬貨を受け付けます。「Coin」という型に定義されているので、例えば50円硬貨など、許可されていない硬貨を入れようとするとエラーになります。これも型システムのおかげで、誤ったお金を使うことを防いでいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490265/359febd0-0d5c-b91b-896f-7169a1b33703.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490265/9ce5cc4c-a5e2-fd2c-3b56-492904eca84b.png)

型を定義することで、どんなデータが使えるかをはっきり決めておけるので、プログラムの中で間違ったデータが使われるのを防ぐことができます。これが型システムの大きな強みです。

## 開発者にも優しい😊
型システムはプログラムを正確にしてくれるだけでなく、開発者にとっても安心感を与えてくれます。型があることで、間違いを防ぎやすくなり、開発中に問題を発見して修正しやすくなります。これによって、より確実なコードを書き、エラーの少ないシステムを作ることができるようになります。

また、型を使うことでチーム開発のときにも役立ちます。コードにどんな値が入るのかが明確にわかるので、他の人がコードを見たときにも理解しやすくなります。これによって、チーム全体の効率が上がり、より良いコミュニケーションができるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490265/cfa70358-6f02-badd-0e29-ff90aa469ffe.png)

型が定義されていると…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490265/2469978f-e3ab-2547-a028-bddd328fa6ba.png)

伝わる！！？

型システムのもう一つの良い点は、コードの説明がしやすくなることです。型を見ると、その変数や関数がどんなデータを扱うのかがすぐにわかるので、新しい人がチームに入ったときもコードを理解しやすくなります。これで学ぶ時間が減り、全体的に効率が良くなります。

このように、型システムはプログラムを書くときの強い味方です。


# まとめ
TSの型システムについて、ゆるく解説してみました。ぜひ、活用していきましょう。


【PR】TypeScriptの入門記事も書いてるので、そちらもチェックして頂けるとたいへんうれしいです。

https://ar-aca.tech/posts/typescript-learning-roadmap/