モノレポでTypeScriptパッケージを作成する - 基本編

モノレポでTypeScriptパッケージを作成する - 基本編

開発

はじめに

こんにちは。今回はモノレポ(Monorepo)について解説します。モノレポとは、複数のプロジェクトやパッケージを1つのリポジトリで一元管理する手法です。

TypeScriptパッケージを作る利点

モノレポでTypeScriptパッケージを作成することで、以下のような利点があります:

  • 型定義の共有による開発効率の向上
  • コードの再利用性の向上
  • プロジェクト間の一貫性維持

モノレポの基本構造


├── apps/                # アプリケーション
│ ├── web/               # Webアプリケーション
│ ├── admin/             # 管理画面
│ └── mobile/            # モバイルアプリ
│
├── packages/            # 共有パッケージ
│ ├── config/            # 設定ファイル
│ ├── ui/                # UIコンポーネント
│ ├── utils/             # ユーティリティ
│ └── types/             # 型定義パッケージ

```

このように、アプリケーションとパッケージを明確に分離した構成を取ります。

今回作るパッケージについて

@sample/typesというパッケージを作っていきます。これは、プロジェクト全体で使う型定義をまとめたパッケージです。APIのレスポンス型とか、共通のデータ構造とか、そういうのを全部ここで管理します!

さぁ、実際に作っていこう!

まずはpackage.jsonから

package.jsonは、パッケージの顔みたいなもの。ここでいろんな設定をしていきます:

{
  "name": "@sample/types",
  "version": "0.0.0",
  "private": true,
  "sideEffects": false, // Tree Shakingを効かせるためのフラグ!
  "main": "./dist/index.js", // CommonJS用のエントリーポイント
  "module": "./dist/index.mjs", // ES Modules用
  "types": "./dist/index.d.ts", // TypeScript用の型定義ファイル
  "files": [
    "dist/**" // 公開するファイルはdistディレクトリの中身だけ!
  ],
  "scripts": {
    "lint": "eslint src/", // コードの品質チェック
    "typecheck": "tsc --noEmit", // 型チェック
    "build": "tsup", // ビルド
    "dev": "tsup --watch", // 開発モード
    "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" // お掃除用
  },
  "devDependencies": {
    "@types/node": "^20.11.16",
    "eslint": "^8.57.0",
    "eslint-config-next": "^14.1.0",
    "tsup": "^8.0.1", // 超便利なビルドツール!
    "typescript": "^5.3.3"
  }
}

TypeScriptの設定もバッチリ!

tsconfig.jsonは、TypeScriptの動作を決める大事な設定ファイル:

{
  "compilerOptions": {
    "target": "es2018", // モダンなJavaScriptを使うぞ!
    "lib": ["esnext"], // 最新の機能を使えるように
    "module": "esnext", // モジュールシステムも最新式
    "moduleResolution": "node", // Node.js方式で解決
    "declaration": true, // 型定義ファイルを出力
    "declarationMap": true, // ソースマップも出力
    "sourceMap": true, // デバッグ用のソースマップ
    "outDir": "./dist", // 出力先ディレクトリ
    "strict": true, // 厳格な型チェック
    "esModuleInterop": true, // import文を使いやすく
    "skipLibCheck": true, // 型チェックを最適化
    "forceConsistentCasingInFileNames": true // ファイル名の大文字小文字を厳格に
  },
  "include": ["src/**/*"], // コンパイル対象
  "exclude": ["node_modules", "dist"]
}

tsup.config.tsの設定

import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['cjs', 'esm'],
  dts: true,
  splitting: false,
  sourcemap: true,
  clean: true,
});

型定義の実装

基本的な型の設計

// 基本的な型定義をエクスポート
export type Maybe<T> = T | null | undefined;

// 共通のレスポンス型
export interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

// ページネーション用の型
export interface PaginationParams {
  page: number;
  limit: number;
}

export interface PaginatedResponse<T> extends ApiResponse<T[]> {
  total: number;
  currentPage: number;
  totalPages: number;
}

ビルドと動作確認

ビルドプロセス

1. 以下のコマンドでビルドを実行:

pnpm build

2. 生成される成果物:

  • dist/index.js (CommonJS)
  • dist/index.mjs (ES Modules)
  • dist/index.d.ts (型定義)

他のパッケージやアプリケーションから以下のように使用できます:

import { ApiResponse, Maybe } from '@sample/types';

// 型の使用例
const response: ApiResponse<User> = {
  data: user,
  status: 200,
  message: 'Success',
};

const optionalValue: Maybe<string> = null;

まとめ

このように、モノレポ環境でTypeScriptパッケージを作成することで、以下のメリットが得られます:

  • プロジェクト全体で一貫した型定義の使用
  • 開発効率の向上
  • コードの再利用性の促進

```

```