メインコンテンツまでスキップ

第20章:TS開発は2択(王道)🛣️🧭

この章は「TypeScript で開発ループ(保存→即反映)」を作るときの 王道2ルートを、迷わず選べるようにする回です😆✨ (Node は v24 が Active LTS / v25 が Current / v22 が Maintenance LTS という並びです🟢)(Node.js) (TypeScript は 5.9 系が安定ラインで配布されています)(typescriptlang.org)


🎯 この章のゴール

  • 「TS開発って結局どう回すの?」が 2パターンに整理できる🧠✨
  • Docker/Compose 上で、どっちでも 保存→自動再実行にできる🔁🐳
  • 「なぜそうなるのか」も、ザックリ腑に落ちる🤝😊

✅ 結論:TS開発はこの2択!

ルートA:tsc -wdist/ を作って Nodeで実行 🧱➡️🏃

  • TS → JS に ちゃんとビルドしてから動かす
  • 開発中は tsc -w(watch)で 自動ビルド
  • 実行側は node --watch dist/...自動再起動
  • 「本番に近い形」で安心感が強い💪

TypeScript 側の watch(--watch)は公式機能です(typescriptlang.org) Node 側にも --watch があり、変更で再起動できます👀(Node.js)


ルートB:tsx などで TS を直接実行 🏃‍♂️💨

  • TS を そのまま実行して最速ループ
  • さらに tsx watch ...保存→即再実行
  • 初心者が詰まりがちな ESM/CJS 周りも “だいぶ丸く” しやすい😇

tsx は「node の代わりに使う」感覚で OK、watch モードも用意されています(tsx) ただし tsx 自体は型チェックしない(=別で型チェック工程を置くのが推奨)というのが大事ポイントです🧷(tsx)


🧭 どっちを選ぶ?超ざっくり診断(迷ったらコレ!)

  • とにかく早く動かして学習を進めたい → ルートB(tsx)🏎️💨
  • 本番に近い流れ(ビルド→実行)を最初から体に入れたい → ルートA(tsc -w)🧱
  • チームで「dist を成果物」として扱う予定 → ルートA が相性◎👥
  • 小さめAPI・スクリプト・検証が多い → ルートB が超ラク😆

📦 共通:最小サンプル(この章の動作確認用)🧪✨

フォルダ構成(例)📁

myapp/
src/
index.ts
package.json
tsconfig.json
Dockerfile
compose.yml

src/index.ts(超ミニ HTTP サーバ)🌐

import http from "node:http";

const server = http.createServer((req, res) => {
res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
res.end("Hello TS! 👋\n");
});

server.listen(3000, () => {
console.log("listening on http://localhost:3000 🚀");
});

ルートA:tsc -wdist/node --watch 🧱🔁

1) tsconfig.json(まずは素直に dist 出力)🧊✨

{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"rootDir": "src",
"outDir": "dist",

"strict": true,
"esModuleInterop": true,
"sourceMap": true
},
"include": ["src/**/*"]
}

2) package.json scripts(2ターミナルが一番わかりやすい)🧑‍💻🧑‍💻

{
"scripts": {
"dev:build": "tsc -w",
"dev:run": "node --watch dist/index.js",
"build": "tsc",
"start": "node dist/index.js"
}
}
  • ターミナル①:npm run dev:build(TS を監視して dist 生成)🔁
  • ターミナル②:npm run dev:run(dist の変更で再起動)👀🔁(Node.js)

💡 Node の --watch は「変更を見て再起動する」機能。開発の “自動リロード” を Node 単体でやれる感じです👀✨(Node.js)

3) Compose で動かす(例)🐳

services:
app:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
- node_modules:/app/node_modules
command: sh -lc "npm run dev:build & npm run dev:run"
volumes:
node_modules:
  • sh -lc "A & B"2プロセス同居(簡易)🧪
  • もう少し綺麗にやるなら concurrently などに任せる手もあります(後でOK)😉

ルートB:tsx watch で TS 直実行 🏃‍♂️💨

1) scripts:開発は tsx、型チェックは tsc に任せる🧩🧷

tsx は便利だけど 型チェックはしないので、役割分担が王道です✅(tsx)

{
"scripts": {
"dev": "tsx watch src/index.ts",
"type-check": "tsc --noEmit",
"start": "node dist/index.js"
}
}
  • dev:保存したら即再実行(tsx watch)🔁(tsx)
  • type-check:型だけチェック(CI や pre-commit、または気になったら手で実行)🧷(tsx)

2) Compose(tsx ルートはとにかくシンプル)🪄

services:
app:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
- node_modules:/app/node_modules
command: npm run dev
volumes:
node_modules:

📌 tsx は「node の代わりに使える」ノリで OK です(Node フラグも渡せます)😆(tsx)


🧯 ありがち事故と対処(Docker + watch 編)🐳👀

① 「保存しても watch が反応しない/遅い」🫠

watch は OS のファイル通知に依存するので、環境によって差が出ます📎 TypeScript 側も fs.watch を使うため、その挙動差や制限が公式に説明されています(typescriptlang.org)

さらに Docker Desktop + WSL2 では、Linux コンテナが inotify(変更通知)を受け取れるのは “Linux 側のファイルシステム上のファイル” が基本、というベストプラクティスが明記されています📌(Docker Documentation)

👉 つまり、困ったらまずこれ:

  • プロジェクトを WSL の Linux 側に置く(/mnt/c 配下より Linux 側が安定しやすい)🐧🪟(Docker Documentation)

② 「tsx は動くけど、型ミスに気づきにくい」😇

tsx は「型チェックは別でやってね」設計です🧷(tsx) 👉 対処:

  • npm run type-check を “節目” で叩く(CI に入れるのが最強)✅

🤖 AI(例:GitHub の Copilot / OpenAI 系ツール)に投げる一言テンプレ✨

  • 「tsx ルートで、devtsx watchtype-checktsc --noEmit の scripts を作って」🤖📝
  • 「tsc -w で dist 出して、node --watch で再起動する compose コマンドを書いて」🐳🔁
  • 「watch が効かない時の Windows + WSL2 の注意点を短くまとめて」🪟🐧

✅ この章のまとめ(チートシート)📌✨

  • ルートA(tsc -w → dist → node):本番に近い、安心感つよい🧱
  • ルートB(tsx watch):最速で回せる、学習が進む🏎️
  • tsx は型チェックしないtsc --noEmit を別に置くのが王道🧷(tsx)
  • Docker + watch が怪しい時は WSL2 のファイル置き場が最重要ポイントになりがち📌(Docker Documentation)

次の第21章は、この2択のうち **「まずはラクな方(tsx ルート)で成功体験」**を、もっと手順化して “確実に動く” ところまで持っていく回にすると気持ちよく繋がります😆🔥