TypeScript エラー修正: プロパティが型に存在しない (ts2339)

beginner🔵 TypeScript2026-03-19| TypeScript 4.x / 5.x、Node.js、React、Next.js、その他 TypeScript プロジェクト全般 (VS Code、WebStorm、tsc CLI)

Error Message

Property 'name' does not exist on type '{}'. ts(2339)
#typescript#プロパティ##ts2339

エラーの内容

プロパティにアクセスすると、TypeScriptがすぐに赤い下線を引きます:

const user = {};
console.log(user.name); // Property 'name' does not exist on type '{}'. ts(2339)

関数の戻り値、APIレスポンス、Reactのstateでも同様のエラーが発生します:

function getUser() {
  return {};
}
const user = getUser();
console.log(user.name); // ts(2339)

TypeScriptは型を{}(プロパティを持たない空のオブジェクト)と推論しました。nameが存在するという根拠がないため、コンパイルできません。

原因

TypeScriptは構造的型付けを採用しています。型には明示的に宣言したプロパティのみが含まれ、何も仮定されません。{}と書いたり、アノテーションなしで素のオブジェクトを返したりすると、TypeScriptは推論できる最も狭い型を選択します。その型へのプロパティアクセスはすべてts(2339)を引き起こします。

よくある原因:

  • {}で初期化し、後からプロパティを追加するオブジェクト
  • 汎用オブジェクト(object{}Record<string, unknown>)を返すと型付けされた関数
  • anyとして型付けされ、どこかで{}に絞り込まれたAPI/JSONレスポンス
  • インターフェース定義の欠如または誤り
  • 条件付きで追加されたが型に反映されていないプロパティ

修正方法1:インターフェースまたは型を定義する

まずここから始めましょう。オブジェクトの形状を明示的に宣言する方法が、スケールする修正方法です:

interface User {
  name: string;
  age?: number; // オプション
}

const user: User = { name: 'Alice' };
console.log(user.name); // OK

関数の戻り値にも、戻り値の型をアノテーションしましょう:

function getUser(): User {
  return { name: 'Alice' };
}

const user = getUser();
console.log(user.name); // OK

修正方法2:型アサーション

データの形状はわかっているが、TypeScriptにはわからない場合は、asを使って伝えましょう:

const raw = JSON.parse(response) as { name: string };
console.log(raw.name); // OK

オブジェクトを段階的に構築する場合:

const user = {} as User;
user.name = 'Alice';
console.log(user.name); // OK

**注意:**アサーションは型チェックを完全にバイパスします。実際のデータが一致しない場合、警告なしにランタイムエラーが発生します。形状が確実にわかっている場合にのみ使用してください。

修正方法3:インデックスシグネチャを持つ型を使用する

動的なキーは別の問題です。コンパイル時にプロパティ名がわからない場合は、インデックスシグネチャが答えです:

const user: Record<string, unknown> = { name: 'Alice' };
console.log(user['name']); // OK

// より具体的な値の型を使用:
const config: Record<string, string> = {};
config.theme = 'dark'; // OK

修正方法4:型ガードで型を絞り込む

APIレスポンスはunknownとして受け取ることが多いです。型ガードを使ってアクセス前に形状を検証しましょう:

function hasName(obj: unknown): obj is { name: string } {
  return typeof obj === 'object' && obj !== null && 'name' in obj;
}

const data: unknown = JSON.parse(response);

if (hasName(data)) {
  console.log(data.name); // TypeScriptはこれが安全だと認識する
}

修正方法5:オプショナルチェーン(真にオプショナルなプロパティ向け)

プロパティが存在する場合としない場合があり、それが意図的なこともあります。型でオプショナルとして宣言し、呼び出し側で不在のケースを処理しましょう:

interface User {
  name?: string;
}

const user: User = {};
console.log(user.name ?? 'Anonymous'); // OK

注意すべき点として、オプショナルチェーンだけではts(2339)は修正されません。プロパティはオプショナルとしてマークされていても、型定義に含まれている必要があります。

修正方法6:既存の型を拡張する

ライブラリの型はカスタムフィールドをカバーしないことがほとんどです。最初から再定義せず、拡張しましょう:

// カスタム認証フィールドを持つExpress Request
import { Request } from 'express';

interface AuthRequest extends Request {
  user?: { name: string };
}

app.get('/', (req: AuthRequest, res) => {
  console.log(req.user?.name); // OK
});

修正方法7:再利用可能な関数にジェネリクスを使用する

ジェネリクスは再利用性の問題を解決します。必要なプロパティを要求するよう型パラメータを制約しましょう:

function getName<T extends { name: string }>(obj: T): string {
  return obj.name; // OK — Tには'name'が保証されている
}

getName({ name: 'Alice', age: 30 }); // 動作する
getName({}); // ts(2345) — 関数内部に埋もれず、呼び出し側で検出される

修正の確認

--noEmitオプションを付けてコンパイラを実行し、出力ファイルを生成せずにプロジェクト全体をチェックします:

npx tsc --noEmit

出力がクリーンであれば、ts(2339)は解消されています。VS Codeでは、保存した直後に赤い下線が消えます。変数にホバーすると、ツールチップに{}ではなくインターフェース名が表示されるはずです。

予防策

  • tsconfig.jsonstrictモードを有効にする"strict": true。ts(2339)や関連エラーを、より大きな問題に波及する前に早期に検出できます。
  • APIレスポンスにanyを使わない。unknownを使い、型ガードで絞り込むことで型システムの正確性を保ちます。
  • **実装前に型を書く。**インターフェースはすぐに定義でき、後のデバッグ時間を大幅に節約できます。
  • satisfies演算子を使用する(TypeScript 4.9以降)。型を拡大せずにオブジェクトが型に一致するか検証できます:
const user = { name: 'Alice', age: 30 } satisfies User;
console.log(user.name); // OK — 型はUserに拡大されず、狭いまま保たれる

Related Error Notes