Skip to main content

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.

note

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โ€‹

FunctionDuplicate keysReturns
keyByLast wins{ key: T }
groupByAll 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" };