JavaScriptやTypeScriptを学んでいると、配列の要素を探すときに
「とりあえず indexOf を使えばいい」
と考えがちです。
しかし、実装を進めていると次のような疑問にぶつかります。
- オブジェクト(連想配列)に indexOf が使えない
- 期待した位置が返ってこない
- -1 になる理由が分からない
私自身、未経験からIT企業への転職に向けてTypeScriptを学ぶ中で、
ToDoリストのデータ管理をしている際にこの問題に直面しました。
結論から言うと、
indexOf は「配列専用」であり、連想配列(オブジェクト)では使えません。
この記事では、その理由と、
indexOfが使えない場合の正しい対処法 を整理します。
indexOfは何をしているメソッドなのか
まず前提として、indexOf は 配列のメソッド です。
const arr = ["a", "b", "c"];
arr.indexOf("b"); // 1
このとき、indexOf は
配列の中身を先頭から順番に比較し、完全一致した要素の位置を返す
という処理をしています。
重要なのは、
値そのものを比較している
という点です。
なぜ連想配列(オブジェクト)では使えないのか
そもそも連想配列は「配列ではない」
JavaScriptでよく言われる「連想配列」は、正確には オブジェクト です。
const task = {
id: 1,
title: "勉強する",
done: false
};
この構造は、
- 順番を持つ配列
- 数字のインデックス
ではなく、
キーと値の組み合わせ で管理されています。
そのため、配列専用メソッドである indexOf は使えません。
オブジェクトを配列に入れた場合でも注意が必要
次のようなケースも、初心者がよく混乱します。
const tasks = [
{ id: 1, title: "勉強する" },
{ id: 2, title: "運動する" }
];
tasks.indexOf({ id: 1, title: "勉強する" }); // -1
一見すると同じオブジェクトに見えますが、indexOf は 参照(メモリ上の同一性) を比較します。
つまり、
- 中身が同じ
- でも別のオブジェクト
という場合、見つからないのが正しい挙動です。
indexOfが使えないときの正しい対処法
findIndexを使う(最もよく使う)
オブジェクトの配列から特定の要素を探す場合、
最も一般的なのが findIndex です。
const index = tasks.findIndex(t => t.id === 1);
この方法なら、
- オブジェクトのプロパティで比較できる
- 条件を自由に書ける
というメリットがあります。
findを使って要素そのものを取得する
「位置」ではなく「中身」が欲しい場合は find を使います。
const task = tasks.find(t => t.id === 1);
ToDoリストなどでは、
indexよりも要素そのものが必要な場面の方が多い
ため、こちらの方が自然なケースも多いです。
filterを使って複数取得する
条件に合うものが複数ある可能性がある場合は、filter を使います。
const doneTasks = tasks.filter(t => t.done === true);
これは indexOf では実現できない使い方です。
オブジェクト単体ならキーで直接アクセスする
配列ではなく、単なるオブジェクトであれば、
そもそも探す必要はありません。
const task = {
id: 1,
title: "勉強する"
};
console.log(task.title);
このように、
キーが分かっているなら直接アクセスする
のが最もシンプルです。
なぜこの理解が重要なのか
indexOfが使えない問題は、
単なるメソッドの知識不足ではありません。
- 配列とオブジェクトの違い
- 値と参照の違い
- データ構造の選び方
これらを理解していないと、
バグの原因になります。
特にReactやTypeScriptで状態管理を行う場合、
「配列の中のオブジェクトをどう特定するか」
は頻出テーマです。
まとめ
indexOf が使えるのは、
- プリミティブ値
- 同一参照の要素
- 純粋な配列
だけです。
連想配列(オブジェクト)や、
オブジェクトの配列を扱う場合は、
findIndexfindfilter
を使うのが正解です。
未経験からTypeScriptを学ぶ中で感じたのは、
「メソッドを覚えるより、データ構造を理解する方が大事」
ということでした。

コメント