keyBy()
keyBy<
T,K>(array,iteratee):Partial<Record<K,T>>
Creates an object composed of keys generated from the results of running each element through iteratee.
In case of duplicate keys, the last value wins.
Type Parameters
T: T
The type of elements in the array.
K: K extends PropertyKey
The type of the key returned by the iteratee.
Parameters
array: readonly T[]
The array to iterate over.
iteratee: (value) => K
A function that returns the key for each element.
Returns: Partial<Record<K, T>>
An object with keys mapping to elements.
Since
2.0.0
Performance
O(n) time & space.
Also known as
indexBy (Remeda, Ramda) · keyBy (Lodash, es-toolkit) · objectify (Radashi) · ❌ (Effect, Modern Dash, Antfu)
Example
const users = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 3, name: 'Bob' }
];
keyBy(users, (u) => u.id);
// => { 1: { id: 1, name: 'John' }, 2: { id: 2, name: 'Jane' }, 3: { id: 3, name: 'Bob' } }
keyBy(['apple', 'banana', 'cherry'], (s) => s[0]);
// => { a: 'apple', b: 'banana', c: 'cherry' }
How it works?
Creates an object where each element is stored under a computed key. Last value wins for duplicate keys.
keyBy vs groupBy
| Function | Duplicate keys | Returns |
|---|---|---|
keyBy | Last wins | { key: T } |
groupBy | All kept | { key: T[] } |
Use Cases
Create lookup tables for instant access by ID 📌
Transform an array into an object indexed by unique identifier. Perfect for normalizing API responses, caching entities, or quick O(1) lookups.
const users = [
{ id: "u1", name: "Alice", role: "admin" },
{ id: "u2", name: "Bob", role: "user" },
{ id: "u3", name: "Charlie", role: "user" },
];
const usersById = keyBy(users, (u) => u.id);
// => {
// u1: { id: "u1", name: "Alice", role: "admin" },
// u2: { id: "u2", name: "Bob", role: "user" },
// u3: { id: "u3", name: "Charlie", role: "user" }
// }
const alice = usersById["u1"];
// => { id: "u1", name: "Alice", role: "admin" }
Index configuration objects by key property 📌
Map settings or config items for quick retrieval by name or code. Ideal for feature flags, locale settings, or environment configurations.
const features = [
{ code: "DARK_MODE", enabled: true, description: "Enable dark theme" },
{ code: "BETA_UI", enabled: false, description: "New UI experiment" },
{ code: "ANALYTICS", enabled: true, description: "Track user events" },
];
const featureFlags = keyBy(features, (f) => f.code);
// => {
// DARK_MODE: { code: "DARK_MODE", enabled: true, ... },
// BETA_UI: { code: "BETA_UI", enabled: false, ... },
// ANALYTICS: { code: "ANALYTICS", enabled: true, ... }
// }
if (featureFlags["DARK_MODE"]?.enabled) {
applyDarkTheme();
}
Map relational data for join-like operations
Index related entities to efficiently merge data from multiple sources. Useful for combining API responses, denormalizing data, or building relationships.
const orders = [
{ orderId: 1, productId: "p1", quantity: 2 },
{ orderId: 2, productId: "p3", quantity: 1 },
{ orderId: 3, productId: "p2", quantity: 5 },
];
const products = [
{ sku: "p1", name: "Keyboard", price: 79 },
{ sku: "p2", name: "Mouse", price: 29 },
{ sku: "p3", name: "Monitor", price: 299 },
];
const productsBySku = keyBy(products, (p) => p.sku);
const enrichedOrders = orders.map((order) => ({
...order,
product: productsBySku[order.productId],
total: (productsBySku[order.productId]?.price ?? 0) * order.quantity,
}));
Normalize API response for a Redux/Zustand store 📌
Convert an array of entities into a normalized { byId, allIds } structure for state management.
The most common real-world pattern for keyBy in any app using Redux, Zustand, or similar stores.
const apiResponse = [
{ id: "p1", title: "Build UI", status: "done" },
{ id: "p2", title: "Write tests", status: "in-progress" },
{ id: "p3", title: "Deploy", status: "todo" },
];
const normalized = {
byId: keyBy(apiResponse, (item) => item.id),
allIds: apiResponse.map((item) => item.id),
};
// normalized.byId["p2"] => { id: "p2", title: "Write tests", status: "in-progress" }
// normalized.allIds => ["p1", "p2", "p3"]
// Fast update without scanning the array
normalized.byId["p2"] = { ...normalized.byId["p2"], status: "done" };