Lodash _.findKey() method
What you’ll learn
- How
_.findKey(object, [predicate])returns the first own string key whose value satisfies the predicate—orundefinedwhen nothing matches. - The four predicate shorthands: function, string property,
[key, value]pair, and partial-deep matcher object. - Why the matcher object uses nesting, not dotted paths like
'a.b.c'. - Try each example in the editor (
?tryit=1,2,3) with Lodash from a CDN.
Prerequisites
Comfortable with Array.prototype.find; _.findKey is the same idea applied to an object’s keys.
- Truthy-ish thinking: the predicate’s return value is evaluated for truthiness, so anything non-falsy short-circuits the search.
- Lodash iteratee shorthands: string, array, and object shapes that Lodash converts to a function under the hood.
- Own vs inherited keys: only own enumerable string keys are visited—same as
Object.keys.
Overview
_.findKey scans an object’s own enumerable string keys in order. For each one it calls the predicate with (value, key, object) and returns the key of the first truthy result—or undefined if it walks the whole object without finding a match.
Returns the key
Unlike _.find (which returns the value), _.findKey hands back the matching property name so you can index back in.
Short-circuits on first match
Iteration stops as soon as the predicate returns truthy—cheap for large objects with an early hit.
Four shorthand shapes
Pass a function, a string property name, a [key, value] array, or a matcher object for partial-deep equality.
Syntax
_.findKey(object, [predicate=_.identity]) - object: the source object whose own enumerable string keys are scanned.
- predicate (optional): any value that
_.iterateeaccepts; defaults to_.identity(find the first key whose value is truthy). - Predicate signature:
(value, key, object) => boolean. - Returns: the matching key (a string), or
undefinedwhen nothing matches.
Object matcher: find by a value’s property
Pass a plain object as the predicate and Lodash treats it as a partial-deep matcher against each value. Below, we hunt for the entry whose color is "yellow".
import findKey from "lodash/findKey";
const produce = {
apple: { color: "red", type: "fruit" },
banana: { color: "yellow", type: "fruit" },
carrot: { color: "orange", type: "vegetable" }
};
findKey(produce, { color: "yellow" });
// -> "banana"
findKey(produce, { type: "vegetable" });
// -> "carrot"
findKey(produce, { color: "purple" });
// -> undefined (no match) Function predicate — remember the argument order
The predicate receives (value, key, object)—value first, like _.find. Forgetting that and reading key off the first parameter is the #1 mistake.
import findKey from "lodash/findKey";
const users = {
user1: { age: 25, isAdmin: true },
user2: { age: 30, isAdmin: false },
user3: { age: 22, isAdmin: true }
};
findKey(users, (user) => user.isAdmin);
// -> "user1" (first match wins)
findKey(users, "isAdmin");
// -> "user1" (string shorthand: truthy on that property)
findKey(users, (user, key) => key.endsWith("3") && user.age < 30);
// -> "user3" (full (value, key, object) signature) Nested matcher: nest the predicate, don’t use dot paths
The object-shorthand matcher checks each predicate key as a literal property name. To match nested data, write the predicate with the same nesting; for a dotted-string path use _.matchesProperty via [path, value].
import findKey from "lodash/findKey";
const accounts = {
jane: { details: { name: "Jane Doe", age: 28, isAdmin: false } },
root: { details: { name: "Admin User", age: 35, isAdmin: true } }
};
findKey(accounts, { "details.isAdmin": true });
// -> undefined
// "details.isAdmin" is a LITERAL key on the value; no such key exists.
findKey(accounts, { details: { isAdmin: true } });
// -> "root" (nested matcher)
findKey(accounts, ["details.isAdmin", true]);
// -> "root" ([path, value] shorthand expects a dotted path) 📋 _.findKey vs _.findLastKey vs _.find
| Topic | _.findKey | _.findLastKey | _.find |
|---|---|---|---|
| Returns | Matching key (string) | Matching key (string) | Matching value |
| Works on | Objects | Objects | Arrays & objects |
| Iteration order | Forward (insertion) | Reverse | Forward (insertion) |
| No-match result | undefined | undefined | undefined |
| Predicate args | (value, key, object) | (value, key, object) | (value, indexOrKey, collection) |
Reach for _.findKey when you need the property name; if you only care about the matched value, _.find is a touch more direct.
Pitfalls to avoid
Predicate gets (value, key), not (key, value)
If you swap them you’ll test the value as if it were a key. The fix is to remember: it’s _.find’s signature plus a key argument—value comes first.
Dotted keys in object matcher are NOT paths
Old write-ups sometimes show { 'a.b.c': value } and claim it matches nested data. It doesn’t—_.matches reads "a.b.c" as a literal property name. Use a nested object or the [path, value] shorthand.
Returning 0, "", or null is “no match”
Lodash checks predicate truthiness. If a real domain value should match but is falsy, wrap with an explicit === expected check.
Guard undefined before indexing
obj[_.findKey(obj, pred)] becomes obj[undefined] when there’s no match—rarely what you want. Check the key first or use _.find if you just need the value.
❓ FAQ
Summary
- Purpose: find the first own string key in an object whose value satisfies the predicate.
- Remember: predicate is
(value, key, object); no match returnsundefined; matcher object uses nesting, not dots. - Next: Lodash _.findLastKey(), or the official Lodash docs for _.findKey.
The predicate is invoked with (value, key, object)—value FIRST, key second. This mirrors _.find for collections; it’s the opposite of Object.keys(obj).find((key) => ...), where you naturally start from the key.
6 people found this page helpful
