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.