Back

JavaScriptで「TypeError: Cannot Read Property of Undefined」を修正する方法

JavaScriptで「TypeError: Cannot Read Property of Undefined」を修正する方法

「Cannot read property of undefined」エラーは、他のほとんどのランタイムエラーよりも多くのJavaScriptアプリケーションを停止させます。APIからデータを取得する場合でも、Reactコンポーネントをレンダリングする場合でも、ユーザー入力を処理する場合でも、このJavaScript TypeErrorは、コードがまだ存在しないものからプロパティにアクセスしようとしたときに発生します。

この記事では、このエラーが発生する理由、オプショナルチェイニングなどの最新のJavaScriptソリューションを使用した修正方法、およびReactやTypeScriptアプリケーションでこのエラーを防ぐ方法について説明します。

重要なポイント

  • TypeErrorは、JavaScriptがundefinedまたはnullからプロパティを読み取ろうとしたときに発生します
  • オプショナルチェイニング(?.)とNull合体演算子(??)は、最新のJavaScriptでクリーンなソリューションを提供します
  • Reactのエラーは、未初期化の状態や非同期データの準備不足から発生することが多いです
  • TypeScriptの厳密なnullチェックは、コンパイル時にこれらのエラーを検出します

最新のJavaScriptでこのエラーが発生する理由

TypeErrorは、JavaScriptがundefinedからプロパティを読み取ろうとしたときに発生します。ブラウザのバージョンによって「Cannot read property」または「Cannot read properties」と表示されますが、どちらも同じランタイムエラーを指します。

実際によくある原因

非同期データがまだ準備できていない

// APIデータがまだ到着していない
const [user, setUser] = useState()
return <div>{user.name}</div> // TypeError!

未初期化のReact状態

const [profile, setProfile] = useState() // デフォルトでundefined
useEffect(() => {
  console.log(profile.id) // 即座にクラッシュ
}, [])

深いプロパティアクセス

// サーバーレスポンスが不完全な可能性がある
const city = response.data.user.address.city // どのレベルでもundefinedの可能性

これらのシナリオには共通のタイミング問題があります:データが存在する前にコードが実行されます。Reactでは、最初のレンダリング中や、開発環境でのStrictModeの二重レンダリングが未初期化の状態の問題を露呈させるときに、これがよく発生します。

最新のソリューション:オプショナルチェイニングとNull合体演算子

JavaScriptは現在、冗長なガードパターンを置き換えるエレガントなソリューションを提供しています。これらのES2020+機能は、今日の標準的なアプローチです。

オプショナルチェイニング(?.)

オプショナルチェイニングは、undefinedまたはnullに遭遇すると評価を停止し、エラーをスローする代わりにundefinedを返します:

// 最新のアプローチ(ES2020+)
const userName = user?.profile?.name
const firstItem = items?.[0]
const result = api?.getData?.()

// 古いガードパターン(まだ機能しますが冗長)
const userName = user && user.profile && user.profile.name

Null合体演算子(??)

オプショナルチェイニングとNull合体演算子を組み合わせて、フォールバック値を提供します:

// null/undefinedの場合のみフォールバック(空文字列や0ではない)
const displayName = user?.name ?? 'Anonymous'
const itemCount = data?.items?.length ?? 0

// OR演算子との違い
const port = config?.port || 3000  // 0、''、falseでフォールバック
const port = config?.port ?? 3000  // null/undefinedの場合のみ

フレームワーク固有のパターン

React:未定義の状態を適切に処理する

Reactの未定義エラーは、未初期化の状態や非同期操作中によく発生します:

function UserProfile() {
  // undefinedではなくnullで初期化
  const [user, setUser] = useState(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    fetchUser().then(data => {
      setUser(data)
      setLoading(false)
    })
  }, [])

  // 条件付きレンダリングでエラーを防ぐ
  if (loading) return <div>Loading...</div>
  if (!user) return <div>No user found</div>
  
  // ここではuserプロパティに安全にアクセス可能
  return <div>{user.name}</div>
}

**重要:**二重レンダリングの問題を「修正」するためにStrictModeを無効にしないでください。代わりに、状態を適切に初期化し、条件付きレンダリングを使用してください。

TypeScript:コンパイル時の防止

TypeScriptのnull安全性は、厳密なnullチェックを通じて、ランタイム前にこれらのエラーを検出します:

// tsconfig.json
{
  "compilerOptions": {
    "strictNullChecks": true
  }
}

interface User {
  name: string
  email?: string // オプショナルプロパティ
}

function greetUser(user: User | undefined) {
  // TypeScriptエラー:オブジェクトが'undefined'の可能性があります
  console.log(user.name) // ❌
  
  // 正しいアプローチ
  console.log(user?.name) // ✅
  if (user) console.log(user.name) // ✅
}

警告:「修正」として非null表明(user!.name)を使用しないでください。これはTypeScriptの安全性をバイパスし、ランタイムエラーを引き起こす可能性があります。

予防のためのベストプラクティス

状態を意味のある形で初期化する

// 悪い例:undefined状態
const [data, setData] = useState()

// 良い例:明示的な初期状態
const [data, setData] = useState(null)
const [items, setItems] = useState([])
const [config, setConfig] = useState({ theme: 'light' })

非同期データにローディング状態を使用する

function DataDisplay() {
  const [state, setState] = useState({
    data: null,
    loading: true,
    error: null
  })

  // 状態に基づいてレンダリング
  if (state.loading) return <Spinner />
  if (state.error) return <Error message={state.error} />
  if (!state.data) return <Empty />
  
  return <DataView data={state.data} />
}

APIレスポンスを検証する

async function fetchUserSafely(id) {
  try {
    const response = await api.get(`/users/${id}`)
    
    // 使用前に構造を検証
    if (!response?.data?.user) {
      throw new Error('Invalid response structure')
    }
    
    return response.data.user
  } catch (error) {
    console.error('Fetch failed:', error)
    return null // 予測可能なフォールバックを返す
  }
}

まとめ

「Cannot read property of undefined」TypeErrorは、基本的にタイミングとデータの可用性に関するものです。最新のJavaScriptのオプショナルチェイニング(?.)とNull合体演算子(??)は、古いガードパターンを置き換えるクリーンで読みやすいソリューションを提供します。Reactでは、適切な状態の初期化と条件付きレンダリングがほとんどの問題を防ぎ、TypeScriptの厳密なnullチェックはコンパイル時にエラーを検出します。

重要なのは、undefined値がJavaScriptの非同期世界では自然なものであることを認識し、それらが発生しないことを期待するのではなく、明示的に処理することです。

よくある質問

Reactコンポーネントは即座にレンダリングされ、初期状態がundefinedの場合や、データが読み込まれる前にネストされたプロパティにアクセスしている場合、エラーが発生します。常に、null、空配列、または必要な構造を持つオブジェクトなど、適切なデフォルト値で状態を初期化してください。

オプショナルチェイニングは、最新のJavaScriptエンジンではパフォーマンスへの影響がほぼありません。可読性と安全性の利点は、マイクロ最適化の懸念をはるかに上回ります。パフォーマンスクリティカルなループで実証されている場合を除き、自由に使用してください。

ブラウザのデバッガーを使用して、その行の前にブレークポイントを設定し、コンソールで各レベルを検査します。または、一時的に各レベルを個別にログ出力して、チェーンがどこで壊れているかを特定します。

try-catchは予期しないエラーを処理するためのものであり、適切なnullチェックの代わりにはなりません。予想されるundefined値には、オプショナルチェイニングと条件付きレンダリングを使用してください。try-catchは、ネットワーク障害、パースエラー、本当に例外的なケースのために予約しておきましょう。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay