はじめてのTypeScriptプログラミング入門 30日コース | Generics・Utility Types・Class・Module - Day 27:Module

TypeScript 30日で身につけるTypeScript
スポンサーリンク
スポンサーリンク

Day 27:Moduleで「ファイル分割」と「役割分担」を身につける

Day 27では、TypeScriptの Module(モジュール) を使って、 コードをきれいに「ファイルごとに分割する」練習をしていきます。

テーマはこうです。

商品管理プログラムを types.ts / products.ts / utils.ts / main.ts に分割する。

ここで扱うキーワードは次のとおりです。

  • export
  • import
  • Named Export
  • Default Export
  • ファイル分割

「ひとつの大きなファイルに全部書く」の卒業式のような回です。 役割ごとにファイルを分けることで、 コードがぐっと読みやすく、保守しやすくなっていきます。

Moduleとは何か:ファイルごとに「小さな世界」を作る

Moduleのざっくりしたイメージ

TypeScript(そして現代のJavaScript)では、 1ファイル = 1モジュール という考え方が基本になっています。

  • あるファイルの中で export したものだけが、 他のファイルから import できます。
  • export していないものは、そのファイルの「内側だけのもの」です。

この仕組みによって、

  • 「外に見せたいもの」
  • 「内側だけで使いたいもの」

をきれいに分けることができます。

exportとimportの基本

Named Export(名前付きエクスポート)

Named Exportは、

「複数のものを名前付きで外に出す」方法

です。

// types.ts
export type Product = {
  id: number;
  name: string;
  price: number;
};

export type Category = "book" | "food" | "toy";
TypeScript

このように export を付けると、 他のファイルから次のように import できます。

// main.ts
import { Product, Category } from "./types";
TypeScript
  • { Product, Category } のように、 波括弧 {} の中に名前を並べてインポートするのが特徴です。
  • 名前は基本的に「そのまま」使われます(別名を付けることもできます)。

Default Export(デフォルトエクスポート)

Default Exportは、

「そのモジュールの“代表”をひとつだけ外に出す」方法

です。

// utils.ts
export default function formatPrice(price: number): string {
  return `${price.toLocaleString()}円`;
}
TypeScript

このように export default を付けると、 他のファイルから次のように import できます。

// main.ts
import formatPrice from "./utils";
TypeScript
  • 波括弧 {} を使わずに、 好きな名前でインポートできるのが特徴です。
  • そのモジュールの「メイン機能」をひとつだけ外に出したいときに向いています。

今回の構成をざっくり設計する

商品管理プログラムを、次の4ファイルに分けます。

  • types.ts
    • 型定義(Productなど)をまとめる
  • products.ts
    • 商品データや商品関連の関数をまとめる
  • utils.ts
    • 共通の便利関数(ユーティリティ)をまとめる
  • main.ts
    • 実際に処理を動かす「エントリーポイント」

この構成は、実務でもよく使われるパターンです。

Step 1:types.tsで「型」をまとめる

まずは、商品管理で使う型を types.ts に集めます。

// types.ts
// 商品管理で使う型定義をまとめるファイル

// 商品の型
export type Product = {
  id: number;        // 商品ID
  name: string;      // 商品名
  price: number;     // 価格
  category: Category; // カテゴリ
};

// カテゴリの型
export type Category = "book" | "food" | "toy";

// 在庫情報の型
export type Stock = {
  productId: number; // 商品ID
  quantity: number;  // 在庫数
};
TypeScript

ポイント:

  • すべて export を付けているので、 他のファイルから import { Product, Category, Stock } として使えます。
  • 型定義をひとつのファイルにまとめることで、 「型の一覧」を見たいときに types.ts を開けばよくなります。

Step 2:products.tsで「商品データ」と「商品関連の処理」をまとめる

次に、商品データと商品を扱う関数を products.ts にまとめます。

// products.ts
// 商品データと商品関連の処理をまとめるファイル

import { Product, Category, Stock } from "./types";

// 商品一覧(サンプルデータ)
export const products: Product[] = [
  { id: 1, name: "TypeScript入門", price: 2000, category: "book" },
  { id: 2, name: "クッキー詰め合わせ", price: 1500, category: "food" },
  { id: 3, name: "ぬいぐるみ", price: 3000, category: "toy" },
];

// 在庫情報(サンプルデータ)
export const stocks: Stock[] = [
  { productId: 1, quantity: 10 },
  { productId: 2, quantity: 5 },
  { productId: 3, quantity: 2 },
];

// 商品IDから商品を検索する関数
export function findProductById(id: number): Product | undefined {
  return products.find((p) => p.id === id);
}

// カテゴリで商品を絞り込む関数
export function filterProductsByCategory(category: Category): Product[] {
  return products.filter((p) => p.category === category);
}

// 商品IDから在庫数を取得する関数
export function getStockQuantity(productId: number): number {
  const stock = stocks.find((s) => s.productId === productId);
  return stock ? stock.quantity : 0;
}
TypeScript

重要ポイント:

  • import { Product, Category, Stock } from "./types";
    • types.ts で export した型を、ここで import して使っています。
  • products / stocks / findProductById などを export しているので、 main.ts から商品関連の機能をまとめて使えます。
  • 「商品に関することは products.ts を見れば分かる」という 役割分担ができています。

Step 3:utils.tsで「共通の便利関数」をまとめる

次に、価格表示などの共通処理を utils.ts にまとめます。

ここでは、Default ExportとNamed Exportの両方を使ってみます。

// utils.ts
// 共通の便利関数をまとめるファイル

// 価格を「1,234円」のような文字列に整形する関数(Default Export)
export default function formatPrice(price: number): string {
  return `${price.toLocaleString()}円`;
}

// 商品名と価格をまとめて表示用文字列にする関数(Named Export)
export function formatProductLine(name: string, price: number): string {
  return `${name} - ${formatPrice(price)}`;
}
TypeScript

ポイント:

  • export default を使った formatPrice は、 「このモジュールの代表的な関数」という位置づけです。
  • formatProductLine は Named Exportとして、 他の便利関数と並べて増やしていけるイメージです。

Step 4:main.tsで「全体を組み立てて動かす」

最後に、main.ts で各モジュールを組み合わせて、 商品管理プログラムを動かします。

// main.ts
// 商品管理プログラムのエントリーポイント

// 型や商品関連の処理をインポート
import { Product, Category } from "./types";
import {
  products,
  findProductById,
  filterProductsByCategory,
  getStockQuantity,
} from "./products";

// ユーティリティ関数をインポート
import formatPrice, { formatProductLine } from "./utils";

// 商品一覧を表示する関数
function showAllProducts(): void {
  console.log("=== 商品一覧 ===");
  products.forEach((product) => {
    const line = formatProductLine(product.name, product.price);
    const stock = getStockQuantity(product.id);
    console.log(`${line} / 在庫: ${stock}個`);
  });
}

// カテゴリ別に商品を表示する関数
function showProductsByCategory(category: Category): void {
  console.log(`=== カテゴリ: ${category} の商品 ===`);
  const filtered = filterProductsByCategory(category);
  filtered.forEach((product) => {
    console.log(
      `${product.name} / 価格: ${formatPrice(product.price)} / 在庫: ${getStockQuantity(
        product.id
      )}個`
    );
  });
}

// 商品IDで詳細を表示する関数
function showProductDetail(id: number): void {
  console.log(`=== 商品詳細 (ID: ${id}) ===`);
  const product = findProductById(id);

  if (!product) {
    console.log("商品が見つかりませんでした");
    return;
  }

  console.log(`商品名: ${product.name}`);
  console.log(`価格: ${formatPrice(product.price)}`);
  console.log(`カテゴリ: ${product.category}`);
  console.log(`在庫: ${getStockQuantity(product.id)}個`);
}

// 実行例
showAllProducts();
console.log("");
showProductsByCategory("book");
console.log("");
showProductDetail(2);
TypeScript

ここが大事なポイントです:

  • main.ts は「アプリ全体の流れ」を書く場所として、 ロジックの細かい部分は products.ts や utils.ts に任せています。
  • これにより、main.ts を読むだけで 「このプログラムが何をしているか」がざっくり分かるようになります。
  • 役割ごとにファイルを分けることで、 読みやすさ・変更のしやすさ・テストのしやすさが一気に上がります。

4ファイル構成の全体像をもう一度整理する

ここまでの構成を、もう一度ざっくりまとめます。

  • types.ts
    • 型定義(Product / Category / Stock)
    • 他のファイルから import { Product, Category, Stock } として使う
  • products.ts
    • 商品データ(products)
    • 在庫データ(stocks)
    • 商品検索・カテゴリ絞り込み・在庫取得などの関数
  • utils.ts
    • 価格表示などの共通ユーティリティ関数
    • formatPrice(Default Export)
    • formatProductLine(Named Export)
  • main.ts
    • 全体の流れを組み立てるエントリーポイント
    • 商品一覧表示・カテゴリ別表示・詳細表示などの処理

このようにモジュールを分けることで、

  • 「型はここ」
  • 「商品関連のロジックはここ」
  • 「表示用の整形はここ」
  • 「アプリの入口はここ」

というふうに、コードの「地図」がはっきりしてきます。

Day 27 練習テンプレート(まとめて確認用)

最後に、4ファイル分をまとめて確認できるように、 もう一度コードを並べておきます。

types.ts

// types.ts
export type Product = {
  id: number;
  name: string;
  price: number;
  category: Category;
};

export type Category = "book" | "food" | "toy";

export type Stock = {
  productId: number;
  quantity: number;
};
TypeScript

products.ts

// products.ts
import { Product, Category, Stock } from "./types";

export const products: Product[] = [
  { id: 1, name: "TypeScript入門", price: 2000, category: "book" },
  { id: 2, name: "クッキー詰め合わせ", price: 1500, category: "food" },
  { id: 3, name: "ぬいぐるみ", price: 3000, category: "toy" },
];

export const stocks: Stock[] = [
  { productId: 1, quantity: 10 },
  { productId: 2, quantity: 5 },
  { productId: 3, quantity: 2 },
];

export function findProductById(id: number): Product | undefined {
  return products.find((p) => p.id === id);
}

export function filterProductsByCategory(category: Category): Product[] {
  return products.filter((p) => p.category === category);
}

export function getStockQuantity(productId: number): number {
  const stock = stocks.find((s) => s.productId === productId);
  return stock ? stock.quantity : 0;
}
TypeScript

utils.ts

// utils.ts
export default function formatPrice(price: number): string {
  return `${price.toLocaleString()}円`;
}

export function formatProductLine(name: string, price: number): string {
  return `${name} - ${formatPrice(price)}`;
}
TypeScript

main.ts

// main.ts
import { Category } from "./types";
import {
  products,
  findProductById,
  filterProductsByCategory,
  getStockQuantity,
} from "./products";
import formatPrice, { formatProductLine } from "./utils";

function showAllProducts(): void {
  console.log("=== 商品一覧 ===");
  products.forEach((product) => {
    const line = formatProductLine(product.name, product.price);
    const stock = getStockQuantity(product.id);
    console.log(`${line} / 在庫: ${stock}個`);
  });
}

function showProductsByCategory(category: Category): void {
  console.log(`=== カテゴリ: ${category} の商品 ===`);
  const filtered = filterProductsByCategory(category);
  filtered.forEach((product) => {
    console.log(
      `${product.name} / 価格: ${formatPrice(product.price)} / 在庫: ${getStockQuantity(
        product.id
      )}個`
    );
  });
}

function showProductDetail(id: number): void {
  console.log(`=== 商品詳細 (ID: ${id}) ===`);
  const product = findProductById(id);

  if (!product) {
    console.log("商品が見つかりませんでした");
    return;
  }

  console.log(`商品名: ${product.name}`);
  console.log(`価格: ${formatPrice(product.price)}`);
  console.log(`カテゴリ: ${product.category}`);
  console.log(`在庫: ${getStockQuantity(product.id)}個`);
}

// 実行例
showAllProducts();
console.log("");
showProductsByCategory("book");
console.log("");
showProductDetail(2);
TypeScript

Day 27のまとめ

Day 27では、

  • Moduleの基本(export / import)
  • Named ExportとDefault Exportの違い
  • 「型」「商品ロジック」「ユーティリティ」「エントリーポイント」を それぞれ別ファイルに分けるファイル分割の考え方
  • 商品管理プログラムを types.ts / products.ts / utils.ts / main.ts に分割して動かす流れ

を、ステップバイステップで見てきました。

モジュール分割は、 小さなスクリプトから「ちゃんとしたアプリ」に育てていくうえで、 欠かせない考え方です。

ぜひ、今日の構成をベースに、

  • cart.ts を追加してカート機能をモジュール化する
  • user.ts を追加してユーザー管理をモジュール化する

など、少しずつファイルを増やしながら、 「役割ごとにモジュールを分ける感覚」を育ててみてください。


Day 27:Module演習 ― 小さな「多ファイル構成アプリ」を作る

Day 27の演習テーマは、

3〜5ファイル構成のプログラムを作る。

というものです。 ここまで学んできた export / import / Named Export / Default Export を総動員して、 「ひとつのファイルに全部書く」スタイルから卒業していきます。

ここでは、初心者の方でもイメージしやすい ToDo管理ミニアプリ を題材にして、

  • types.ts(型定義)
  • todo.ts(ToDo操作ロジック)
  • utils.ts(ユーティリティ)
  • main.ts(エントリーポイント)

という 4ファイル構成でステップバイステップに組み立てていきます。

モジュール分割のゴールイメージをつかむ

まずは、今回作る構成のざっくりしたイメージです。

  • types.ts
    • ToDoの型やステータスなど、「型」をまとめるファイル
  • todo.ts
    • ToDoの追加・完了・一覧取得など、「ロジック」をまとめるファイル
  • utils.ts
    • 日付フォーマットなど、「便利関数」をまとめるファイル
  • main.ts
    • 実際に処理を動かす「入口」のファイル

このように役割ごとに分けることで、

  • 「型はここ」
  • 「ToDoの操作はここ」
  • 「表示用の整形はここ」
  • 「アプリの流れはここ」

というふうに、コードの地図がはっきりしてきます。

Step 1:types.ts ― 型定義をひとまとめにする

まずは、ToDo管理で使う型を types.ts に集めます。

// types.ts
// ToDo管理で使う型定義をまとめるファイル

// ToDoのステータス
export type TodoStatus = "pending" | "done";

// ToDoアイテムの型
export type TodoItem = {
  id: number;          // 一意なID
  title: string;       // タイトル
  description?: string; // 説明(任意)
  status: TodoStatus;  // ステータス
  createdAt: Date;     // 作成日時
};
TypeScript

ここでのポイント:

  • すべて export を付けているので、他のファイルから import { TodoItem, TodoStatus } として使えます。
  • 型定義をひとつのファイルにまとめることで、「型の一覧」を見たいときは types.ts を開けばOK、という分かりやすい構造になります。

Step 2:todo.ts ― ToDoの操作ロジックをまとめる

次に、ToDoの追加・完了・一覧取得などのロジックを todo.ts にまとめます。

// todo.ts
// ToDoの操作ロジックをまとめるファイル

import { TodoItem, TodoStatus } from "./types";

// 内部で管理するToDo一覧(ここでは簡単のためメモリ上の配列)
const todos: TodoItem[] = [];

// 次のIDを生成するためのカウンタ
let nextId = 1;

// ToDoを追加する関数(Named Export)
export function addTodo(title: string, description?: string): TodoItem {
  const newTodo: TodoItem = {
    id: nextId++,
    title,
    description,
    status: "pending",
    createdAt: new Date(),
  };

  todos.push(newTodo);
  return newTodo;
}

// IDを指定してToDoを完了にする関数
export function completeTodo(id: number): boolean {
  const todo = todos.find((t) => t.id === id);
  if (!todo) {
    return false; // 見つからなかった
  }
  todo.status = "done";
  return true;
}

// ステータスでToDoを絞り込む関数
export function getTodosByStatus(status: TodoStatus): TodoItem[] {
  return todos.filter((t) => t.status === status);
}

// 全てのToDoを取得する関数
export function getAllTodos(): TodoItem[] {
  // 外から直接配列をいじられないようにコピーを返す
  return [...todos];
}
TypeScript

重要なポイント:

  • todos と nextId は export していないので、todo.ts の「内側だけの状態」として隠されています。
  • 外からは addTodo / completeTodo / getTodosByStatus / getAllTodos を通じてしか操作できません。 これが「モジュールの中にロジックを閉じ込める」という考え方です。

Step 3:utils.ts ― 共通の便利関数をまとめる

次に、表示用の整形などのユーティリティを utils.ts にまとめます。 ここでは、Default ExportとNamed Exportの両方を使ってみます。

// utils.ts
// 共通の便利関数をまとめるファイル

// 日付を「YYYY-MM-DD HH:mm」の形式に整形する関数(Default Export)
export default function formatDate(date: Date): string {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  const hour = String(date.getHours()).padStart(2, "0");
  const minute = String(date.getMinutes()).padStart(2, "0");

  return `${year}-${month}-${day} ${hour}:${minute}`;
}

// ToDoアイテムを1行の文字列に整形する関数(Named Export)
import { TodoItem } from "./types";

export function formatTodoLine(todo: TodoItem): string {
  const statusLabel = todo.status === "pending" ? "未完了" : "完了";
  const created = formatDate(todo.createdAt);
  return `[${statusLabel}] (${todo.id}) ${todo.title} / 作成: ${created}`;
}
TypeScript

ポイント:

  • formatDate は export default で出しているので、 他のファイルからは import formatDate from "./utils"; のように、 好きな名前でインポートできます。
  • formatTodoLine は Named Exportとして、 他のユーティリティ関数と並べて増やしていけるイメージです。

Step 4:main.ts ― 全体を組み立てて動かす

最後に、main.ts で各モジュールを組み合わせて、 ToDo管理ミニアプリを動かします。

// main.ts
// ToDo管理ミニアプリのエントリーポイント

import { TodoStatus } from "./types";
import {
  addTodo,
  completeTodo,
  getAllTodos,
  getTodosByStatus,
} from "./todo";
import formatDate, { formatTodoLine } from "./utils";

// 全てのToDoを表示する関数
function showAllTodos(): void {
  console.log("=== 全てのToDo ===");
  const todos = getAllTodos();
  if (todos.length === 0) {
    console.log("ToDoはまだありません");
    return;
  }
  todos.forEach((todo) => {
    console.log(formatTodoLine(todo));
  });
}

// ステータス別にToDoを表示する関数
function showTodosByStatus(status: TodoStatus): void {
  console.log(`=== ステータス: ${status} のToDo ===`);
  const todos = getTodosByStatus(status);
  if (todos.length === 0) {
    console.log("該当するToDoはありません");
    return;
  }
  todos.forEach((todo) => {
    console.log(formatTodoLine(todo));
  });
}

// 実行例:いくつかToDoを追加して操作してみる
function main(): void {
  console.log("=== ToDo管理ミニアプリ ===");
  console.log("現在時刻:", formatDate(new Date()));
  console.log("");

  // ToDoを追加
  const t1 = addTodo("TypeScriptの勉強をする", "Genericsを復習");
  const t2 = addTodo("買い物に行く", "牛乳とパン");
  const t3 = addTodo("運動する");

  console.log("追加したToDoのID:", t1.id, t2.id, t3.id);
  console.log("");

  // 全てのToDoを表示
  showAllTodos();
  console.log("");

  // 2番目のToDoを完了にする
  const success = completeTodo(t2.id);
  console.log(`ID ${t2.id} のToDo完了処理:`, success ? "成功" : "失敗");
  console.log("");

  // ステータス別に表示
  showTodosByStatus("pending");
  console.log("");
  showTodosByStatus("done");
}

// エントリーポイントを呼び出す
main();
TypeScript

ここでの大事なポイント:

  • main.ts は「アプリ全体の流れ」を書く場所として、 ロジックの細かい部分は todo.ts や utils.ts に任せています。
  • これにより、main.ts を読むだけで 「このプログラムが何をしているか」がざっくり分かるようになります。
  • import の行を見ると、「このファイルがどのモジュールに依存しているか」が一目で分かります。

Named ExportとDefault Exportの使い分けを整理する

ここまでの例で、両方のスタイルを使いました。 改めて、使い分けのイメージを整理しておきます。

  • Named Export
    • 複数の関数・型・定数を「名前付き」で外に出したいときに使います。
    • export function addTodo(...) {}
    • import { addTodo } from "./todo";
    • 「このモジュールにはいろいろ入っているよ」という感じ。
  • Default Export
    • 「このモジュールの代表」をひとつだけ外に出したいときに使います。
    • export default function formatDate(...) {}
    • import formatDate from "./utils";
    • 「このモジュールといえばこれ」というメイン機能に向いています。

どちらが正解というわけではなく、 「そのモジュールの役割」に合わせて選んでいくイメージです。

Day 27演習のテンプレートまとめ

最後に、4ファイル構成の全体をもう一度一覧できるようにまとめておきます。

types.ts

// types.ts
export type TodoStatus = "pending" | "done";

export type TodoItem = {
  id: number;
  title: string;
  description?: string;
  status: TodoStatus;
  createdAt: Date;
};
TypeScript

todo.ts

// todo.ts
import { TodoItem, TodoStatus } from "./types";

const todos: TodoItem[] = [];
let nextId = 1;

export function addTodo(title: string, description?: string): TodoItem {
  const newTodo: TodoItem = {
    id: nextId++,
    title,
    description,
    status: "pending",
    createdAt: new Date(),
  };
  todos.push(newTodo);
  return newTodo;
}

export function completeTodo(id: number): boolean {
  const todo = todos.find((t) => t.id === id);
  if (!todo) {
    return false;
  }
  todo.status = "done";
  return true;
}

export function getTodosByStatus(status: TodoStatus): TodoItem[] {
  return todos.filter((t) => t.status === status);
}

export function getAllTodos(): TodoItem[] {
  return [...todos];
}
TypeScript

utils.ts

// utils.ts
import { TodoItem } from "./types";

export default function formatDate(date: Date): string {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  const hour = String(date.getHours()).padStart(2, "0");
  const minute = String(date.getMinutes()).padStart(2, "0");

  return `${year}-${month}-${day} ${hour}:${minute}`;
}

export function formatTodoLine(todo: TodoItem): string {
  const statusLabel = todo.status === "pending" ? "未完了" : "完了";
  const created = formatDate(todo.createdAt);
  return `[${statusLabel}] (${todo.id}) ${todo.title} / 作成: ${created}`;
}
TypeScript

main.ts

// main.ts
import { TodoStatus } from "./types";
import {
  addTodo,
  completeTodo,
  getAllTodos,
  getTodosByStatus,
} from "./todo";
import formatDate, { formatTodoLine } from "./utils";

function showAllTodos(): void {
  console.log("=== 全てのToDo ===");
  const todos = getAllTodos();
  if (todos.length === 0) {
    console.log("ToDoはまだありません");
    return;
  }
  todos.forEach((todo) => {
    console.log(formatTodoLine(todo));
  });
}

function showTodosByStatus(status: TodoStatus): void {
  console.log(`=== ステータス: ${status} のToDo ===`);
  const todos = getTodosByStatus(status);
  if (todos.length === 0) {
    console.log("該当するToDoはありません");
    return;
  }
  todos.forEach((todo) => {
    console.log(formatTodoLine(todo));
  });
}

function main(): void {
  console.log("=== ToDo管理ミニアプリ ===");
  console.log("現在時刻:", formatDate(new Date()));
  console.log("");

  const t1 = addTodo("TypeScriptの勉強をする", "Genericsを復習");
  const t2 = addTodo("買い物に行く", "牛乳とパン");
  const t3 = addTodo("運動する");

  console.log("追加したToDoのID:", t1.id, t2.id, t3.id);
  console.log("");

  showAllTodos();
  console.log("");

  const success = completeTodo(t2.id);
  console.log(`ID ${t2.id} のToDo完了処理:`, success ? "成功" : "失敗");
  console.log("");

  showTodosByStatus("pending");
  console.log("");
  showTodosByStatus("done");
}

main();
TypeScript

Day 27演習のまとめ

今回の演習では、

  • export / import を使ってモジュール間で機能をやり取りする方法
  • Named ExportとDefault Exportの違いと使い分け
  • 3〜5ファイル構成(ここでは4ファイル)のプログラムを 「型」「ロジック」「ユーティリティ」「エントリーポイント」に分けて設計する流れ

を、ToDo管理ミニアプリを通して体験しました。

小さなプログラムでも、 ファイルを分けて役割をはっきりさせるだけで、 ぐっと「本物のアプリ」っぽさが出てきます。

ぜひ、この構成をベースに、

  • user.ts を追加してユーザー管理をモジュール化する
  • storage.ts を追加してローカルストレージ保存機能をモジュール化する

など、少しずつファイルを増やしながら、 「モジュール分割のセンス」を育てていってください。

タイトルとURLをコピーしました