第06章:プロジェクト雛形(TS+テスト+Lintを最小で)🧪
6.1 この章のゴール🎯
- TypeScriptをstrictで書けるようにする🧠✨ (TypeScript)
- **ES Modules(ESM)**で迷子にならない構成にする📦 (Node.js)
- テスト1本が通るところまで到達する✅
- Lintで最低限の事故を防ぐ(保存するたびに安心感UP)🧹 (ESLint)
6.2 まず完成形(ファイル構成)📁✨
これで「なんとなく」から卒業して、プロっぽい開発体験を手に入れよう!🚀✨

package.jsontsconfig.jsoneslint.config.jssrc/total.tssrc/total.test.ts
6.3 手順①:プロジェクト作成(コマンドだけでOK)🛠️💨
mkdir gof-ts-learning
cd gof-ts-learning
npm init -y
code .
6.4 手順②:依存関係を入れる(最小)📦✨
npm i -D typescript vitest eslint @eslint/js typescript-eslint
- テスト:Vitest(TSと相性よくて導入が軽い) (typescript-eslint.io)
- Lint:ESLint v9以降は flat config(
eslint.config.js)が標準 🧹 (ESLint) - TS向けルール:typescript-eslint の推奨構成を使うよ🧩 (Node.js)
6.5 手順③:package.json を整える🧾✨
✅ ここがポイント
- ESMにするなら
"type": "module"を入れる📦(Nodeの公式ドキュメントでも説明あり) (Node.js) - スクリプトを4つだけ用意する(これで学習が回る)🔁
package.json をこうしてね👇
{
"name": "gof-ts-learning",
"version": "1.0.0",
"type": "module",
"private": true,
"scripts": {
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest",
"lint": "eslint ."
}
}
6.6 手順④:tsconfig.json(strict + Node ESM寄り)🧠📦
TypeScriptは modern Nodeなら module: "nodenext" が推奨寄りだよ🧁 (TypeScript)
moduleResolution も nodenext とセットで「import/requireの解決アルゴリズム差」を扱える設計🧭 (TypeScript)
tsconfig.json を作成👇
{
"compilerOptions": {
"target": "ES2022",
"module": "nodenext",
"moduleResolution": "nodenext",
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
💡
strict: trueは「安全系オプションをまとめてON」にするスイッチだよ✨ (TypeScript)
6.7 手順⑤:ESLint(flat config)を置く🧹✨
eslint.config.js を作成👇
(ESLint v9の流儀=flat config!) (ESLint)
import js from "@eslint/js";
import tseslint from "typescript-eslint";
export default [
{ ignores: ["dist/**", "node_modules/**"] },
js.configs.recommended,
...tseslint.configs.recommended
];
- 「TypeScript向けの推奨ルール」をそのまま使うのが一番ラク🧁 (Node.js)
- ここでは 過剰なルール追加はしない(学習の敵=設定沼😵💫)
6.8 手順⑥:最小コード(関数1つ)+テスト1本✅🍰
src/total.ts
export type LineItem = {
name: string;
price: number; // 税抜でも税込でもOK(ここでは数値として扱うだけ)
qty: number;
};
export const calcTotal = (items: readonly LineItem[]): number => {
return items.reduce((sum, x) => sum + x.price * x.qty, 0);
};
src/total.test.ts
ESMだと相対importは拡張子が絡みやすいので、ここでは .js で書くのが安定だよ📦
(NodeのESMは package.json の "type": "module" などで判定される話も公式に載ってる) (Node.js)
import { describe, it, expect } from "vitest";
import { calcTotal } from "./total.js";
describe("calcTotal", () => {
it("合計金額を計算できる", () => {
const total = calcTotal([
{ name: "Latte", price: 450, qty: 2 },
{ name: "Cookie", price: 180, qty: 1 }
]);
expect(total).toBe(1080);
});
});
6.9 動作確認(3つだけ)✅✅✅
npm run typecheck
npm run lint
npm test
全部通ったら勝ち〜〜!🎉✨
6.10 よくあるつまずき(ここだけ見れば復帰できる)🧯😵💫
❓ Q1. Cannot find module './total' とか言われる…
- ESMだと importの解決がシビアになりがち🧩
- まずはこの章の通り、テスト内の相対importは
./total.jsにすると安定しやすいよ📦 - その背景として、Nodeは
package.jsonの"type"などでESM/CJS扱いを決めるよ(公式) (Node.js)
❓ Q2. ESLintがVS Codeで反映されない…
- 拡張機能「ESLint」を入れて、右下の警告が出るなら “Enable” する🧹✨
- 反映されない時は
Ctrl+Shift+P→ “Developer: Reload Window” 🔁
❓ Q3. 「最新のNodeはTSをそのまま実行できるって聞いた!」👀
- できる方向に進んでるよ!(型を剥がして実行する仕組みなど)
- ただ、学習では「確実に動く最小」が最優先なので、まずこの雛形でOK👌✨ (必要になったら、後で“実行方法の選択肢”として追加すれば大丈夫!)
❓ Q4. Vitestの設定で迷子になった…🌀
- 最初は 設定ファイル無しで進めてOK!
- 詰まったら「よくあるエラー集」を見ると早いよ🧯 (typescript-eslint.io)
6.11 この章のAIプロンプト例🤖💬
TypeScriptで「関数1つ+テスト1本」だけの最小例を作りたいです。
制約:
- ESM(package.json は type: module)
- tsconfig strict: true
- テストは Vitest
- import で迷子にならないように、相対importの書き方も含めて提示して
出力:
1) ファイル構成 2) 各ファイルの中身 3) 実行コマンド 4) よくある詰まりポイント
6.12 チェックリスト✅📌(ここが全部OKなら次章へ!)
npm run typecheckが通る✅npm run lintが通る✅npm testが通る✅src/total.tsとsrc/total.test.tsがある✅- 「設定を増やさずに回せる」状態になってる✅🎉
次の第7章から、この土台の上で「共通題材(カフェ注文)」を少しずつ育てていくよ〜☕🧁✨