Skip to content

KeyBy Method

The keyBy() method keys the collection by the given key. If multiple items have the same key, later values will overwrite previous ones.

Basic Syntax

typescript
// Key by property
collect(items).keyBy(key: keyof T)

// Key by callback
collect(items).keyBy(callback: (item: T) => string | number)

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

interface User {
  id: number
  name: string
  email: string
}

const users = collect<User>([
  { id: 1, name: 'John', email: 'john@example.com' },
  { id: 2, name: 'Jane', email: 'jane@example.com' },
  { id: 3, name: 'Bob', email: 'bob@example.com' }
])

// Key by id
const usersById = users.keyBy('id')
console.log(usersById.all())
// {
//   '1': { id: 1, name: 'John', email: 'john@example.com' },
//   '2': { id: 2, name: 'Jane', email: 'jane@example.com' },
//   '3': { id: 3, name: 'Bob', email: 'bob@example.com' }
// }

Using Callback Function

typescript
interface Product {
  id: number
  name: string
  category: string
  sku: string
}

const products = collect<Product>([
  { id: 1, name: 'Laptop', category: 'Electronics', sku: 'LAP001' },
  { id: 2, name: 'Mouse', category: 'Electronics', sku: 'MOU001' },
  { id: 3, name: 'Desk', category: 'Furniture', sku: 'DSK001' }
])

// Key by custom SKU format
const productsBySku = products.keyBy(product => `SKU-${product.sku}`)
console.log(productsBySku.all())
// {
//   'SKU-LAP001': { id: 1, name: 'Laptop', category: 'Electronics', sku: 'LAP001' },
//   'SKU-MOU001': { id: 2, name: 'Mouse', category: 'Electronics', sku: 'MOU001' },
//   'SKU-DSK001': { id: 3, name: 'Desk', category: 'Furniture', sku: 'DSK001' }
// }

Real-world Examples

User Session Management

typescript
interface Session {
  sessionId: string
  userId: number
  lastActivity: Date
  device: string
}

const sessions = collect<Session>([
  { sessionId: 'a1', userId: 1, lastActivity: new Date(), device: 'desktop' },
  { sessionId: 'b2', userId: 2, lastActivity: new Date(), device: 'mobile' },
  { sessionId: 'c3', userId: 1, lastActivity: new Date(), device: 'tablet' }
])

// Key sessions by user ID for quick lookup
const sessionsByUser = sessions.keyBy('userId')
console.log(sessionsByUser.all())
// {
//   '1': { sessionId: 'c3', userId: 1, lastActivity: Date, device: 'tablet' },
//   '2': { sessionId: 'b2', userId: 2, lastActivity: Date, device: 'mobile' }
// }

Cache Management

typescript
interface CacheItem {
  key: string
  value: any
  expiry: Date
  tags: string[]
}

class CacheManager {
  private cache: Collection<{ [key: string]: CacheItem }>

  constructor(items: CacheItem[]) {
    this.cache = collect(items).keyBy('key')
  }

  get(key: string): any {
    const item = this.cache.get(key)
    if (!item || item.expiry < new Date()) {
      return null
    }
    return item.value
  }

  getByTag(tag: string): CacheItem[] {
    return this.cache
      .filter(item => item.tags.includes(tag))
      .all()
  }
}

// Usage
const cacheItems: CacheItem[] = [
  { key: 'user:1', value: { name: 'John' }, expiry: new Date(), tags: ['user'] },
  { key: 'settings:1', value: { theme: 'dark' }, expiry: new Date(), tags: ['settings'] }
]

const cache = new CacheManager(cacheItems)

Advanced Usage

Multi-level Grouping

typescript
interface Order {
  id: number
  customerId: number
  status: string
  date: string
  total: number
}

const orders = collect<Order>([
  { id: 1, customerId: 1, status: 'pending', date: '2024-01-01', total: 100 },
  { id: 2, customerId: 2, status: 'completed', date: '2024-01-01', total: 200 },
  { id: 3, customerId: 1, status: 'completed', date: '2024-01-02', total: 300 }
])

// Key by composite key using callback
const ordersByCustomerAndDate = orders.keyBy(order =>
  `${order.customerId}-${order.date}`
)

console.log(ordersByCustomerAndDate.all())
// {
//   '1-2024-01-01': { id: 1, customerId: 1, status: 'pending', date: '2024-01-01', total: 100 },
//   '2-2024-01-01': { id: 2, customerId: 2, status: 'completed', date: '2024-01-01', total: 200 },
//   '1-2024-01-02': { id: 3, customerId: 1, status: 'completed', date: '2024-01-02', total: 300 }
// }

Dynamic Key Generation

typescript
interface Student {
  id: number
  firstName: string
  lastName: string
  grade: number
}

const students = collect<Student>([
  { id: 1, firstName: 'John', lastName: 'Doe', grade: 85 },
  { id: 2, firstName: 'Jane', lastName: 'Smith', grade: 92 },
  { id: 3, firstName: 'Bob', lastName: 'Johnson', grade: 78 }
])

// Key by full name
const studentsByName = students.keyBy(student =>
  `${student.lastName}, ${student.firstName}`
)

// Key by grade range
const studentsByGrade = students.keyBy((student) => {
  if (student.grade >= 90)
    return 'A'
  if (student.grade >= 80)
    return 'B'
  return 'C'
})

Type Safety

typescript
interface TypedItem {
  id: number
  code: string
  value: number
}

const items = collect<TypedItem>([
  { id: 1, code: 'A', value: 100 },
  { id: 2, code: 'B', value: 200 }
])

// TypeScript ensures type safety
const byId = items.keyBy('id') // ✓ Valid
const byCode = items.keyBy('code') // ✓ Valid
// items.keyBy('nonexistent')          // ✗ TypeScript error

// Type-safe callback
const byCustomKey = items.keyBy((item: TypedItem) => {
  return `${item.code}-${item.id}`
})

Return Value

Returns a new Collection instance with:

  • Keys based on the specified property or callback result
  • Values as the original items
  • Later items overwrite earlier items with the same key

Released under the MIT License.