Cloudflare Workersプロジェクトで、R2ストレージを扱う関数を実装していた。
TypeScriptとしては正常にコンパイルできるが、ESLintがR2Object型を認識せず、no-undefエラーが発生した。
正直なところ、このエラーの原因を特定するのに少し時間がかかった。
TypeScriptの型システムは完璧に動作しているのに、ESLintだけがエラーを出す——この状況は多くの開発者が直面する問題です。
こんな人におすすめ
この記事は以下のような方に役立ちます。
- Cloudflare Workers + R2 で開発をしている
- ESLintの
no-undefエラーに遭遇して困っている - TypeScriptのグローバル型とESLintの違いを理解したい
- 型安全性を保ちながらLintエラーを回避したい
目次
症状
/functions/api/storage/images/list.ts
214:42 error 'R2Object' is not defined no-undef
@cloudflare/workers-typesのtriple-slash directiveを追加しても解決しなかった。
/// <reference types="@cloudflare/workers-types" />
個人的に、この対処法が効かないときは「どうすればいいんだ?」と少し焦りました。
原因
ESLintとTypeScriptの仕組みの違い
ESLintはTypeScriptのtriple-slash directiveで定義されたグローバル型を認識しません。
TypeScriptコンパイラは認識するが、ESLintのno-undefルールは別の仕組みで動作するのです。
なぜこの問題が発生するのか
TypeScriptのtriple-slash directive(/// <reference types="..." />)は、TypeScriptコンパイラ専用の機能です。
これはコンパイル時にのみ参照され、ESLintのようなリンティングツールからは見えません。
ESLintのno-undefルールは、ESLintのドキュメントにある通り、グローバル変数の定義をglobals設定またはexportedコメントで認識します。
TypeScriptの型定義ファイル(.d.ts)で宣言されたグローバル型は、ESLintからは見えないのです。
詳細は、@typescript-eslint/parserのドキュメントで確認できます。
直し方
どの解決策を選ぶべきか、以下のフローチャートで判断できます。
flowchart TD
Start[ESLintのno-undefエラーが発生] --> Q1{型安全性を維持したい?}
Q1 -->|はい| A1[解決策1: インターフェース定義]
Q1 -->|いいえ| Q2{型チェックが不要でOK?}
Q2 -->|はい| A2[解決策2: no-undef無効化]
Q2 -->|いいえ| A3[解決策3: globals設定]
A1 --> R1[✅ 推奨: 型安全性を保てる]
A2 --> R2[⚠️ 注意: 型チェックが緩くなる]
A3 --> R3[⚠️ 注意: 型情報が失われる]
style A1 fill:#c8e6c9
style A2 fill:#fff9c4
style A3 fill:#fff9c4
style R1 fill:#c8e6c9
style R2 fill:#ffe0b2
style R3 fill:#ffe0b2
解決策1: インターフェースを明示的に定義する(推奨)
必要なプロパティのみを持つインターフェースを明示的に定義します。
/**
* R2オブジェクトの必要なプロパティのみを定義
* (ESLint対応: @cloudflare/workers-typesのグローバル型はESLintに認識されないため)
*/
interface R2ObjectLike {
key: string;
uploaded: Date;
size: number;
}
export function parseImageObject(object: R2ObjectLike, r2PublicUrl: string): ImageInfo | null {
// ...
}
実際のR2Object型と互換性があるため、env.STORAGE.list()の結果をそのまま渡せます。
以下の図は、R2から取得したデータがどうやって関数に渡されるかを示したフローです。
sequenceDiagram
participant R2 as R2ストレージ
participant Env as env.STORAGE
participant Func as parseImageObject関数
participant User as ユーザーコード
R2->>Env: list()でR2Objectsを取得
Env->>Func: R2Object[]を渡す
Note over Func: interface R2ObjectLike<br/>で型チェック✅
Func->>User: ImageInfo[]を返す
Note over User: ESLintエラーなし✅
この方法で型安全性も保ちながら、ESLintエラーを回避できました。
解決策2: ESLintのno-undefルールを無効化する
もう一つの方法は、@typescript-eslint/no-undefを使用するか、no-undefルールを無効化することです。
ただし、この方法は型チェックが緩くなる可能性があるため推奨しません。
/* eslint-disable no-undef */
// R2Objectを使用するコード
/* eslint-enable no-undef */
解決策3: globals設定で宣言する
.eslintrc.jsonでglobals設定にR2Objectを追加する方法もあります。
{
"globals": {
"R2Object": "readonly"
}
}
しかし、この方法では型情報が失われるため、解決策1のインターフェース定義が最も安全です。
学び
- ESLintとTypeScriptは型認識の仕組みが異なる
- グローバル型に依存する場合、ESLint用に明示的な型定義が必要なことがある
- 必要なプロパティのみを持つインターフェースを定義することで、型安全性を保ちながらESLintエラーを回避できる
よくある質問(FAQ)
Q. ESLintとTypeScriptのどちらを優先すべきですか?
A. 両方のエラーを解消するのが理想です。
TypeScriptの型チェックは実行時エラーを防ぐために重要です。
一方で、ESLintはコードの一貫性を保つために役立ちます。
インターフェース定義を使えば、両方の要件を満たせます。
Q. 他のCloudflare Workers型でも同様の問題が発生しますか?
A. はい、同様の問題が発生する可能性があります。
R2Bucket、Env、ExecutionContextなど、@cloudflare/workers-typesで定義されるグローバル型すべてで同様の問題が発生します。
同じアプローチでインターフェースを定義することで解決できます。
Q. インターフェース定義が面倒です。もっと簡単な方法はありませんか?
A. no-undefルールを無効化する方法がありますが、推奨しません。
型チェックの緩和はバグの原因になる可能性があるため、最初からインターフェースを定義することをおすすめします。
まとめ
今回の問題から得た教訓をまとめます。
-
ESLintとTypeScriptは別物
- ESLintはTypeScriptのtriple-slash directiveを認識しません
-
明示的な型定義で解決
- 必要なプロパティのみを持つインターフェースを定義することで、両方の要件を満たせます
-
実用的なアプローチ
- 実際の型と互換性があるため、既存のコードにそのまま適用できます
-
同じ問題が他の型でも発生
- Cloudflare Workersのグローバル型すべてで同様の問題が発生する可能性があります
この方法を採用したことで、Lintエラーが解消され、開発体験が改善されました。
確認手順
npm run lintでエラーがないことを確認npm run testでテストが通ることを確認- TypeScriptコンパイルエラーがないことを確認
参考リンク
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "ESLintがCloudflare Workers型を認識しない問題の解決", "description": "Cloudflare WorkersでR2を使用する際、ESLintがR2Object型を認識しないno-undefエラーの原因と解決方法を解説。", "image": "https://wakatchi.dev/wp-content/uploads/2026/01/eslint-cloudflare-workers.png", "datePublished": "2026-01-01", "dateModified": "2026-01-01", "author": { "@type": "Person", "name": "wakatchi" }, "publisher": { "@type": "Organization", "name": "wakatchi.dev", "logo": { "@type": "ImageObject", "url": "https://wakatchi.dev/wp-content/uploads/logo.png" } }, "keywords": "ESLint, TypeScript, Cloudflare Workers, R2, 型定義, no-undef", "articleSection": "Infrastructure", "proficiencyLevel": "Beginner", "dependencies": "ESLint, TypeScript, @cloudflare/workers-types", "operatingSystem": "Any", "programmingLanguage": "TypeScript" } </script>


