概要
Cloudflare Workers で Env 型を手書きしていると、wrangler.jsonc のバインディングを増やすたびに worker/types.ts の Env も手で同期する作業が発生します。wrangler types で生成される worker-configuration.d.ts を取り込めば、バインディング型は自動同期されます。さらに、用途別に Env から派生型を切ると、ハンドラごとの「DB が確実にある」「テスト用に部分的に与える」といった事情を型で表現できます。
本記事は、wrangler types の組み込み + Cloudflare.Env を起点にした派生型設計のテンプレートです。
全体像
wrangler.jsonc ← バインディング定義(D1, KV, Queue, Hyperdrive 等)
↓ wrangler types
worker-configuration.d.ts ← `declare namespace Cloudflare { interface Env { ... } }`
↓ 派生
worker/types.ts
- Env = Cloudflare.Env + オプショナルなシークレット
- RuntimeEnv = Env + 確実にあるバインディング
- TestEnv = Partial<RuntimeEnv>
手順
1. wrangler types の実行と取り込み
npx wrangler types
リポジトリ直下に worker-configuration.d.ts が生成されます。Cloudflare.Env namespace に wrangler.jsonc のバインディングが反映されます。
// worker-configuration.d.ts (生成物の概略)
declare namespace Cloudflare {
interface Env {
DB: D1Database
HYPERDRIVE: Hyperdrive
NOTIFICATION_QUEUE: Queue
SHARE_KV: KVNamespace
SUPABASE_URL: string
// ...
}
}
2. tsconfig に include + ESLint で ignore
// tsconfig.worker.json
{
"compilerOptions": { /* ... */ },
- "include": ["worker/**/*.ts", "shared/**/*.ts"],
+ "include": ["worker/**/*.ts", "shared/**/*.ts", "worker-configuration.d.ts"],
"exclude": ["worker/**/*.test.ts", /* ... */]
}
// eslint.config.js
export default defineConfig([
- globalIgnores(['dist/**', 'tmp/**', '.claude/worktrees/**']),
+ globalIgnores(['dist/**', 'tmp/**', '.claude/worktrees/**', 'worker-configuration.d.ts']),
// ...
])
生成物なので ESLint には触らせません。tsconfig には include して Cloudflare.Env を解決可能にします。
3. Env 型を Cloudflare.Env から派生
// worker/types.ts
import type { QueueMessage } from '@worker/queue-messages'
// Cloudflare.Env (from worker-configuration.d.ts) covers wrangler.jsonc
// bindings. Secrets that may not be set in all environments stay optional.
// Queue<QueueMessage> で payload 型を上書き。
// DB はテスト注入用のスロット(runtime-db が代入する)。
export type Env = Omit<Cloudflare.Env, 'NOTIFICATION_QUEUE'> & {
NOTIFICATION_QUEUE?: Queue<QueueMessage>
DB?: AppDatabase
// 追加のオプショナル secrets
RECAPTCHA_SITE_KEY?: string
RECAPTCHA_SECRET_KEY?: string
STRIPE_SECRET_KEY?: string
STRIPE_WEBHOOK_SECRET?: string
}
ポイント:
Omit<Cloudflare.Env, 'NOTIFICATION_QUEUE'>で生成物の型を一旦取り去って、payload 型 (QueueMessage) で上書きします。生成物の Queue は型パラメータが空なので、自前のメッセージ型で型付け直します- ローカル/プレビュー環境で未設定でも動かしたいシークレットは
?でオプショナルに DBを Cloudflare.Env では required にしておきつつ、こちら側で?にして「テスト時のみ注入」を表現します
4. Runtime/Test 用に派生型を切る
// scheduled/queue ハンドラのように runtime-db 解決後にしか走らないコード用
export type RuntimeEnv = Env & { DB: AppDatabase }
// バインディングの一部だけ与えたい単体テスト用
export type TestEnv = Partial<RuntimeEnv>
派生の目的:
RuntimeEnvを使うハンドラはenv.DBを?.で守らなくて済みますTestEnvは不要なバインディングを毎回モックしなくて良いです(必要な分だけ与えます)
// 使用例
import type { Env, RuntimeEnv, TestEnv } from '@worker/types'
export default {
fetch(req: Request, env: Env) { /* ... */ }, // 一般ハンドラは Env
scheduled(event: ScheduledEvent, env: RuntimeEnv) { /* env.DB が確実にある */ },
queue(batch: MessageBatch, env: RuntimeEnv) { /* 同上 */ },
}
// テスト
const env: TestEnv = { DB: makeFakeDb(), SUPABASE_URL: 'http://localhost:54321' }
学び・気づき
- 生成物 (.d.ts) は手で書かない、include する:
wrangler typesが出すファイルは「ジェネレートしたら触らない」原則を徹底します。tsconfig で include + ESLint で ignore がセット Omit<X, K> & { K: NewType }で型の上書き: 生成物の型を「外して新しい型で足し直す」イディオムは Cloudflare 型定義に限らず汎用的に有用です(Queue → Queue 等)- 同じ Env でも文脈で派生型を切る:
fetchハンドラはEnv、scheduled/queueはRuntimeEnv(DB が確実にある)、テストはTestEnv(部分的)。同じバインディング集合でも前提条件が違う場合は型を分けると assertion/optional chain が減って読みやすいです - シークレットの optional/required は環境ごとの実情に合わせる: 生成物は wrangler.jsonc に書いた variable は required になるが、実際は preview / local で未設定のことが多い → アプリ側の
Envでだけ optional に弱めます。実行時にはassertEnv()的なヘルパーで存在を保証します pre-pushフックで typecheck + lint + test を全部回す:Env型を変えると影響範囲が広いので、push 前にnpm run typecheck/lint/testをまとめて走らせる pre-push を仕込んでおくと、レビュー前に壊れないコードしか出ません- eslint config の
globalIgnores: ESLint v9 のdefineConfig+globalIgnoresで生成物を一括無視。flat config 移行と相性が良いです
アンチパターン
Envを手書き +wrangler.jsoncを手で同期: バインディング追加のたびに型を書き換えることになり、PR レビューでも「同期忘れ」が頻発します- 生成物 .d.ts を
git ignore: CI でwrangler typesを毎回回せば成立するが、ローカル開発で IDE の型解決が遅くなります。コミットしてしまった方が IDE 体験が良いです(PR レビュー時のノイズは多くなる tradeoff) as Envでキャスト: バインディング追加忘れを型で検出できなくなります
次にやりたいこと
worker-configuration.d.tsの自動再生成を pre-commit で回します(wrangler.jsonc 変更時のみ)Cloudflare.Envから CI で型 diff を生成し、PR で Reviewer が把握しやすくしますassertEnv()系のランタイムバリデータを zod で書き、optional を「明示的に存在を確認したら required になる」流れにします
まとめ
Cloudflare Workers で型が散らかってきたら、wrangler types 起点の Cloudflare.Env 派生に倒すと一気に楽になります。生成物 → 一元 Env → RuntimeEnv / TestEnv の3階層で「文脈ごとに前提条件を型で表現」します。

