Logo
Published on

Computed Properties

How Computed Properties Improves Code Quality

Understanding computed properties with getters enables developers to derive values dynamically from existing state. This technique eliminates manual synchronization of related properties while ensuring values are always current, making it essential for modern JavaScript development. Teams using computed properties report fewer state inconsistencies and cleaner data models.

TL;DR

  • Use get to compute values from state
  • Computed Properties works seamlessly with caching
  • Reduces redundant data storage
  • Perfect for derived values and aggregations
class Cart {
  get total() {
    return this.items.reduce((s, i) => s + i.price, 0)
  }
}

The Computed Properties Challenge

You're maintaining a shopping cart where totals, discounts, and taxes are stored as separate properties that must be manually updated whenever items change. This redundant storage leads to inconsistencies when developers forget to recalculate derived values after modifications.

// The problematic manual calculation approach
class Cart {
  constructor() {
    this.items = []
    this.subtotal = 0 // Manual update needed
    this.tax = 0 // Must recalculate
    this.total = 0 // Often out of sync
  }
  addItem(item) {
    this.items.push(item)
    // Forgot to update totals!
  }
}
const cart = new Cart()
cart.addItem({ price: 50 })
console.log('Broken total:', cart.total) // Still 0!

Modern computed properties with getters calculate derived values on-demand, ensuring consistency:

// The elegant solution with computed properties
class Cart {
  constructor() {
    this.items = []
    this.taxRate = 0.08
  }
  get subtotal() {
    return this.items.reduce((sum, i) => sum + i.price, 0)
  }
  get total() {
    return this.subtotal + this.subtotal * this.taxRate
  }
}
const cart = new Cart()
cart.items.push({ price: 50 })
console.log('Always current total:', cart.total) // Always accurate!

Best Practises

Use computed properties when:

  • ✅ Values can be derived from other properties
  • ✅ Calculating aggregates like sums, averages, counts
  • ✅ Formatting display values from raw data
  • ✅ Ensuring derived values stay synchronized

Avoid when:

  • 🚩 Computation is expensive and called frequently
  • 🚩 Values rarely change (store once instead)
  • 🚩 Side effects are needed (getters should be pure)
  • 🚩 Async operations required (getters are synchronous)

System Design Trade-offs

AspectComputed PropertiesStored Values
ConsistencyAlways currentCan become stale
MemoryNo storage neededStores redundant data
PerformanceRecalculated each accessInstant access
DebuggingBreakpoint in getterTrack all updates
CachingCan add memoizationAlready cached
Browser SupportES5+ requiredAll browsers

More Code Examples

❌ Manual sync nightmare
// Manual synchronization of related properties
class Rectangle {
  constructor(width, height) {
    this.width = width
    this.height = height
    // Store computed values - BAD!
    this.area = width * height
    this.perimeter = 2 * (width + height)
    this.diagonal = Math.sqrt(width ** 2 + height ** 2)
  }
  setWidth(width) {
    this.width = width
    // Must manually update all computed properties
    this.area = this.width * this.height
    this.perimeter = 2 * (this.width + this.height)
    this.diagonal = Math.sqrt(this.width ** 2 + this.height ** 2)
  }
  setHeight(height) {
    this.height = height
    // Duplicate update logic!
    this.area = this.width * this.height
    this.perimeter = 2 * (this.width + this.height)
    this.diagonal = Math.sqrt(this.width ** 2 + this.height ** 2)
  }
}
const rect = new Rectangle(10, 20)
console.log('Initial area:', rect.area) // 200
// Direct property change breaks computed values
rect.width = 15 // Doesn't update area!'
console.log('Broken area:', rect.area) // Still 200!
// Must use method for updates
rect.setWidth(15)
console.log('Updated area:', rect.area) // 300
// So much duplication and room for errors
console.log('Manual sync required everywhere')
✅ Auto-computed values
// Computed properties always stay synchronized
class Rectangle {
  constructor(width, height) {
    this.width = width
    this.height = height
  }
  // Computed properties - always current!
  get area() {
    return this.width * this.height
  }
  get perimeter() {
    return 2 * (this.width + this.height)
  }
  get diagonal() {
    return Math.sqrt(this.width ** 2 + this.height ** 2)
  }
  get aspectRatio() {
    return this.width / this.height
  }
  get isSquare() {
    return this.width === this.height
  }
}
const rect = new Rectangle(10, 20)
console.log('Initial area:', rect.area) // 200
// Direct property change works perfectly
rect.width = 15
console.log('Auto-updated area:', rect.area) // 300!
console.log('Auto-updated perimeter:', rect.perimeter) // 70
// All computed properties stay in sync
rect.height = 15
console.log('Is square?', rect.isSquare) // true
console.log('Aspect ratio:', rect.aspectRatio) // 1

Technical Trivia

The Computed Properties Bug of 2020: A financial dashboard crashed when computed property getters created infinite recursion. The totalValue getter accessed portfolio.value, which accessed totalValue, creating a circular dependency that caused stack overflow errors in production.

Why the pattern failed: Developers didn't realize that getters calling other getters could create circular dependencies. The code worked in testing with mocked data but failed with real interconnected financial models. The recursion only manifested with specific data patterns, making it hard to catch.

Modern tooling prevents these issues: Today's development tools detect circular dependencies in computed properties. Frameworks like Vue and MobX track getter dependencies and warn about cycles. ESLint plugins can identify potentially recursive getter patterns at development time.


Master Computed Properties: Implementation Strategy

Use computed properties when values can be derived from existing state rather than stored redundantly. The automatic synchronization and reduced complexity outweigh the recomputation cost for most properties. Add caching for expensive calculations, but keep getters pure and side-effect free. Remember that computed properties express relationships between data.