findの基本的な動きと戻り値のイメージ
find は、配列の中から「条件を満たす最初の要素」を1つだけ返すメソッドです。
もし条件を満たす要素が1つも見つからなかった場合は、undefined を返します。
const array = [5, 12, 8, 130, 44];
const found = array.find(el => el > 10);
// found の中身: 12
// 型: number | undefined
TypeScriptここで大事なのは、「見つかるかもしれないし、見つからないかもしれない」という性質が、そのまま戻り値の型に反映されていることです。
TypeScript はこの仕様を踏まえて、find の戻り値を常に「要素の型 | undefined」として扱います。
なぜ戻り値の型が「T | undefined」になるのか
JavaScriptの仕様がそのまま型に反映されている
JavaScriptの Array.prototype.find は、
「条件を満たす要素があればその値を返す。なければ undefined を返す」と定義されています。
TypeScriptはこの仕様を忠実に型に落とし込んでいるので、
配列の要素型が T のとき、find の戻り値は必ず T | undefined になります。
const nums = [1, 2, 3, 4]; // number[]
const result = nums.find(n => n > 2);
// 型: number | undefined
TypeScript「絶対に見つかるはず」と人間が思っていても、
TypeScriptは「見つからない可能性もある」として扱います。
だからこそ、result にすぐプロパティアクセスしようとすると、
「Object is possibly ‘undefined’」というエラーが出るわけです。
findの戻り値をそのまま使うときに起きる典型的なエラー
「Object is possibly ‘undefined’」が出るパターン
type Item = { id: number; name: string };
const items: Item[] = [
{ id: 1, name: "Taro" },
{ id: 2, name: "Hanako" }
];
const found = items.find(item => item.id === 2);
// found: Item | undefined
// found.name; // エラー: Object is possibly 'undefined'
TypeScriptTypeScriptは「found が Item のときもあれば、undefined のときもある」と見ているので、
そのまま found.name にアクセスすると危険だと判断します。
ここで大事なのは、TypeScriptは「ロジック上は必ず見つかるはず」という前提を信用しないということです。
常に「見つからないケースもある」として扱うことで、安全側に倒しています。
undefinedをちゃんと扱うための基本パターン
if文でundefinedをチェックする
一番素直で安全なのは、「undefined かどうかを先に判定する」書き方です。
const found = items.find(item => item.id === 2);
if (found === undefined) {
// 見つからなかった場合の処理を書く
} else {
// ここでは found は Item 型として扱える
console.log(found.name);
}
TypeScriptif (found === undefined) で分岐すると、else の中では found の型が Item に絞り込まれます。
TypeScript的にも、人間的にも一番分かりやすいパターンです。
null合体演算子(??)で「見つからなかったときの代わり」を決める
「見つからなかったときは、代わりの値を使いたい」というケースなら、?? が使えます。
const result = nums.find(n => n > 10) ?? 0;
// result: number
TypeScriptfind が undefined を返した場合だけ、右側の 0 が使われます。
これで「戻り値から undefined を消して、純粋な number にする」ことができます。
「絶対に見つかる」と分かっているときの扱い方
非nullアサーション(!)で「ここは本当にある」と宣言する
「この配列と条件の組み合わせなら、ロジック上絶対に見つかる」と自分で保証できる場合、! を使って「ここでは undefined じゃない」とコンパイラに宣言することもできます。
const found = items.find(item => item.id === 1)!;
// 型: Item
console.log(found.name);
TypeScriptただし、これは完全に自己責任です。
もし実際には見つからなかった場合、実行時にエラーになります。
「本当に100%そう言い切れるか?」を自分に問い直してから使うべきテクニックです。
型述語(type predicate)とfindの組み合わせ
特定の型だけを見つけたい場合
filter と同じく、find にも「型を絞り込む関数(型述語)」を渡すことができます。
type Item = { id: number; name: string } | { id: number; deleted: true };
function isActive(item: Item): item is { id: number; name: string } {
return "name" in item;
}
const items: Item[] = [
{ id: 1, name: "Taro" },
{ id: 2, deleted: true }
];
const found = items.find(isActive);
// 型: { id: number; name: string } | undefined
TypeScriptここでも戻り値は ... | undefined のままですが、
「見つかったときの型」がちゃんと { id: number; name: string } に絞り込まれています。
あとはさっきと同じように、undefined をどう扱うかを決めればOKです。
初心者がまず掴んでおきたい「findの戻り値型」の感覚
find の戻り値型の本質は、たったひとつです。
「見つかるかもしれないし、見つからないかもしれない」 → T | undefined
だからこそ、
undefined を if でちゃんと分岐する?? で「見つからないときの代わり」を決める
どうしてもなら ! で「ここは絶対ある」と宣言する
この3パターンのどれで扱うかを、その場その場で選ぶことになります。
「find は“必ず見つかる”とは限らない」
この前提を型レベルで強制してくれるおかげで、
「見つからなかったときのことを考え忘れていた」というバグを、コンパイル時にかなり潰せるようになります。
