Skip to content
On this page

Pinia Getters

Getters是Pinia Store中的计算属性,用于从State派生数据。它们类似于Vue组件中的computed属性,会自动追踪依赖并在依赖变化时重新计算。本章将详细介绍Getters的使用方法、高级特性和最佳实践。

Getters基础

定义和使用Getters

typescript
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
    items: [] as Item[],
    user: {
      name: 'John',
      age: 30
    }
  }),
  
  getters: {
    // 基础getter - 无参数
    doubleCount: (state) => state.count * 2,
    
    // 带逻辑的getter
    isEven: (state) => state.count % 2 === 0,
    
    // 复杂计算的getter
    summary: (state) => {
      return `Count is ${state.count}, items: ${state.items.length}, user: ${state.user.name}`
    },
    
    // 访问其他getter
    doubleCountPlusOne: (state) => {
      // 注意:在getter中使用this访问其他getter
      return this.doubleCount + 1
    }
  }
})

interface Item {
  id: string
  name: string
  price: number
}

在组件中使用Getters

vue
<template>
  <div>
    <p>Count: {{ counterStore.count }}</p>
    <p>Double Count: {{ counterStore.doubleCount }}</p>
    <p>Is Even: {{ counterStore.isEven }}</p>
    <p>Summary: {{ counterStore.summary }}</p>
    <p>Double Count + 1: {{ counterStore.doubleCountPlusOne }}</p>
    
    <button @click="counterStore.count++">Increment</button>
  </div>
</template>

<script setup>
import { useCounterStore } from '@/stores/counter'

const counterStore = useCounterStore()
</script>

带参数的Getters

返回函数的Getters

typescript
export const useUserStore = defineStore('user', {
  state: () => ({
    users: [
      { id: '1', name: 'Alice', role: 'admin', department: 'IT' },
      { id: '2', name: 'Bob', role: 'user', department: 'HR' },
      { id: '3', name: 'Charlie', role: 'user', department: 'IT' },
      { id: '4', name: 'Diana', role: 'admin', department: 'Finance' }
    ] as User[]
  }),
  
  getters: {
    // 根据ID获取用户
    getUserById: (state) => {
      return (id: string) => {
        return state.users.find(user => user.id === id)
      }
    },
    
    // 根据角色过滤用户
    getUsersByRole: (state) => {
      return (role: string) => {
        return state.users.filter(user => user.role === role)
      }
    },
    
    // 根据部门过滤用户
    getUsersByDepartment: (state) => {
      return (department: string) => {
        return state.users.filter(user => user.department === department)
      }
    },
    
    // 搜索用户
    searchUsers: (state) => {
      return (query: string) => {
        return state.users.filter(user => 
          user.name.toLowerCase().includes(query.toLowerCase())
        )
      }
    },
    
    // 获取用户统计信息
    getUserStats: (state) => {
      return () => {
        const total = state.users.length
        const admins = state.users.filter(u => u.role === 'admin').length
        const itDept = state.users.filter(u => u.department === 'IT').length
        
        return {
          total,
          admins,
          adminPercentage: total > 0 ? (admins / total) * 100 : 0,
          itDept
        }
      }
    }
  }
})

interface User {
  id: string
  name: string
  role: string
  department: string
}

在组件中使用带参数的Getters

vue
<template>
  <div>
    <h2>User Management</h2>
    
    <!-- 搜索功能 -->
    <div>
      <input 
        v-model="searchQuery" 
        placeholder="Search users..." 
        @input="performSearch"
      />
    </div>
    
    <!-- 显示搜索结果 -->
    <div v-if="searchResults.length > 0">
      <h3>Search Results:</h3>
      <ul>
        <li v-for="user in searchResults" :key="user.id">
          {{ user.name }} ({{ user.role }} - {{ user.department }})
        </li>
      </ul>
    </div>
    
    <!-- 部门过滤 -->
    <div>
      <h3>Filter by Department:</h3>
      <button 
        v-for="dept in departments" 
        :key="dept"
        @click="filterByDepartment(dept)"
        :class="{ active: currentDepartment === dept }"
      >
        {{ dept }} ({{ getUsersByDepartment(dept).length }})
      </button>
    </div>
    
    <!-- 显示过滤结果 -->
    <div>
      <h3>Users in {{ currentDepartment }}:</h3>
      <ul>
        <li v-for="user in filteredUsers" :key="user.id">
          {{ user.name }} ({{ user.role }})
        </li>
      </ul>
    </div>
    
    <!-- 统计信息 -->
    <div>
      <h3>Statistics:</h3>
      <p>Total Users: {{ userStats.total }}</p>
      <p>Admins: {{ userStats.admins }} ({{ userStats.adminPercentage.toFixed(1) }}%)</p>
      <p>IT Department: {{ userStats.itDept }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()
const { getUsersByDepartment, searchUsers, getUserStats } = userStore

const searchQuery = ref('')
const currentDepartment = ref('All')

// 使用storeToRefs保持响应性
const { users } = storeToRefs(userStore)

const departments = computed(() => {
  return [...new Set(users.value.map(user => user.department))]
})

const searchResults = computed(() => {
  if (!searchQuery.value) return []
  return searchUsers(searchQuery.value)
})

const filteredUsers = computed(() => {
  if (currentDepartment.value === 'All') {
    return users.value
  }
  return getUsersByDepartment(currentDepartment.value)
})

const userStats = computed(() => {
  return getUserStats()
})

const performSearch = () => {
  // 搜索逻辑在computed中处理
}

const filterByDepartment = (dept) => {
  currentDepartment.value = dept
}
</script>

<style scoped>
.active {
  font-weight: bold;
  background-color: #007bff;
  color: white;
}
</style>

Getter中的复杂逻辑

计算和聚合

typescript
export const useAnalyticsStore = defineStore('analytics', {
  state: () => ({
    events: [
      { id: '1', type: 'click', value: 10, timestamp: Date.now() - 86400000 },
      { id: '2', type: 'view', value: 5, timestamp: Date.now() - 43200000 },
      { id: '3', type: 'click', value: 15, timestamp: Date.now() - 3600000 },
      { id: '4', type: 'purchase', value: 100, timestamp: Date.now() - 1800000 }
    ] as AnalyticsEvent[],
    
    userInteractions: [
      { userId: '1', action: 'login', timestamp: Date.now() - 7200000 },
      { userId: '1', action: 'click', timestamp: Date.now() - 3600000 },
      { userId: '2', action: 'login', timestamp: Date.now() - 1800000 }
    ] as UserInteraction[]
  }),
  
  getters: {
    // 基础统计
    totalEvents: (state) => state.events.length,
    totalValue: (state) => state.events.reduce((sum, event) => sum + event.value, 0),
    
    // 按类型分组
    eventsByType: (state) => {
      const grouped: Record<string, AnalyticsEvent[]> = {}
      state.events.forEach(event => {
        if (!grouped[event.type]) {
          grouped[event.type] = []
        }
        grouped[event.type].push(event)
      })
      return grouped
    },
    
    // 类型统计
    eventCountsByType: (state) => {
      const counts: Record<string, number> = {}
      state.events.forEach(event => {
        counts[event.type] = (counts[event.type] || 0) + 1
      })
      return counts
    },
    
    // 平均值计算
    averageValueByType: (state) => {
      const sums: Record<string, number> = {}
      const counts: Record<string, number> = {}
      
      state.events.forEach(event => {
        sums[event.type] = (sums[event.type] || 0) + event.value
        counts[event.type] = (counts[event.type] || 0) + 1
      })
      
      const averages: Record<string, number> = {}
      Object.keys(sums).forEach(type => {
        averages[type] = sums[type] / counts[type]
      })
      
      return averages
    },
    
    // 时间范围过滤
    getEventsInTimeRange: (state) => {
      return (startTime: number, endTime: number) => {
        return state.events.filter(event => 
          event.timestamp >= startTime && event.timestamp <= endTime
        )
      }
    },
    
    // 最近事件
    recentEvents: (state) => {
      const oneHourAgo = Date.now() - 3600000
      return state.events.filter(event => event.timestamp >= oneHourAgo)
    },
    
    // 用户活跃度
    getUserActivity: (state) => {
      const activity: Record<string, number> = {}
      state.userInteractions.forEach(interaction => {
        activity[interaction.userId] = (activity[interaction.userId] || 0) + 1
      })
      return activity
    },
    
    // 转换率计算
    conversionRate: (state) => {
      const totalClicks = state.events.filter(e => e.type === 'click').length
      const totalPurchases = state.events.filter(e => e.type === 'purchase').length
      return totalClicks > 0 ? (totalPurchases / totalClicks) * 100 : 0
    }
  }
})

interface AnalyticsEvent {
  id: string
  type: string
  value: number
  timestamp: number
}

interface UserInteraction {
  userId: string
  action: string
  timestamp: number
}

高级过滤和排序

typescript
export const useProductStore = defineStore('product', {
  state: () => ({
    products: [
      { id: '1', name: 'Laptop', price: 1200, category: 'Electronics', rating: 4.5, inStock: true },
      { id: '2', name: 'Phone', price: 800, category: 'Electronics', rating: 4.2, inStock: true },
      { id: '3', name: 'Book', price: 20, category: 'Education', rating: 4.8, inStock: false },
      { id: '4', name: 'Headphones', price: 150, category: 'Electronics', rating: 4.0, inStock: true },
      { id: '5', name: 'Desk', price: 300, category: 'Furniture', rating: 4.6, inStock: true }
    ] as Product[],
    
    filters: {
      category: null as string | null,
      minPrice: 0,
      maxPrice: Infinity,
      inStockOnly: false,
      minRating: 0
    },
    
    sortBy: 'name' as 'name' | 'price' | 'rating',
    sortOrder: 'asc' as 'asc' | 'desc'
  }),
  
  getters: {
    // 基础过滤产品
    filteredProducts: (state) => {
      return state.products.filter(product => {
        // 类别过滤
        if (state.filters.category && product.category !== state.filters.category) {
          return false
        }
        
        // 价格过滤
        if (product.price < state.filters.minPrice || product.price > state.filters.maxPrice) {
          return false
        }
        
        // 库存过滤
        if (state.filters.inStockOnly && !product.inStock) {
          return false
        }
        
        // 评分过滤
        if (product.rating < state.filters.minRating) {
          return false
        }
        
        return true
      })
    },
    
    // 排序后的产品
    sortedProducts: (state) => {
      const products = [...this.filteredProducts] // 使用this访问其他getter
      
      return products.sort((a, b) => {
        let comparison = 0
        
        switch (state.sortBy) {
          case 'name':
            comparison = a.name.localeCompare(b.name)
            break
          case 'price':
            comparison = a.price - b.price
            break
          case 'rating':
            comparison = a.rating - b.rating
            break
        }
        
        return state.sortOrder === 'asc' ? comparison : -comparison
      })
    },
    
    // 分类统计
    categoryStats: (state) => {
      const stats: CategoryStats = {}
      
      state.products.forEach(product => {
        if (!stats[product.category]) {
          stats[product.category] = {
            count: 0,
            avgPrice: 0,
            totalValue: 0,
            products: []
          }
        }
        
        const categoryStat = stats[product.category]
        categoryStat.count++
        categoryStat.totalValue += product.price
        categoryStat.products.push(product)
      })
      
      // 计算平均价格
      Object.values(stats).forEach(stat => {
        stat.avgPrice = stat.count > 0 ? stat.totalValue / stat.count : 0
      })
      
      return stats
    },
    
    // 价格范围
    priceRange: (state) => {
      if (state.products.length === 0) {
        return { min: 0, max: 0 }
      }
      
      const prices = state.products.map(p => p.price)
      return {
        min: Math.min(...prices),
        max: Math.max(...prices)
      }
    },
    
    // 推荐产品(高评分且有库存)
    recommendedProducts: (state) => {
      return state.products
        .filter(product => product.rating >= 4.5 && product.inStock)
        .sort((a, b) => b.rating - a.rating)
        .slice(0, 3) // 只取前3个
    },
    
    // 产品总数统计
    productStats: (state) => {
      const total = state.products.length
      const inStock = state.products.filter(p => p.inStock).length
      const outOfStock = total - inStock
      
      return {
        total,
        inStock,
        outOfStock,
        inStockPercentage: total > 0 ? (inStock / total) * 100 : 0
      }
    }
  },
  
  actions: {
    setCategoryFilter(category: string | null) {
      this.filters.category = category
    },
    
    setPriceRange(min: number, max: number) {
      this.filters.minPrice = min
      this.filters.maxPrice = max
    },
    
    setInStockOnly(inStockOnly: boolean) {
      this.filters.inStockOnly = inStockOnly
    },
    
    setMinRating(minRating: number) {
      this.filters.minRating = minRating
    },
    
    setSort(sortBy: 'name' | 'price' | 'rating', sortOrder: 'asc' | 'desc = 'asc') {
      this.sortBy = sortBy
      this.sortOrder = sortOrder
    }
  }
})

interface Product {
  id: string
  name: string
  price: number
  category: string
  rating: number
  inStock: boolean
}

interface CategoryStats {
  [category: string]: {
    count: number
    avgPrice: number
    totalValue: number
    products: Product[]
  }
}

Getter性能优化

使用computed缓存

typescript
import { computed } from 'vue'

export const useOptimizedStore = defineStore('optimized', {
  state: () => ({
    largeDataset: Array.from({ length: 10000 }, (_, i) => ({
      id: i.toString(),
      value: Math.random() * 100,
      category: ['A', 'B', 'C'][i % 3],
      active: i % 2 === 0
    })) as DataItem[],
    
    filters: {
      category: null as string | null,
      minValue: 0,
      maxValue: 100
    }
  }),
  
  getters: {
    // 使用computed包装复杂计算以获得缓存
    expensiveCalculatedData: (state) => {
      return computed(() => {
        // 这个计算会被缓存,只有当依赖变化时才重新计算
        return state.largeDataset
          .filter(item => {
            if (state.filters.category && item.category !== state.filters.category) {
              return false
            }
            if (item.value < state.filters.minValue || item.value > state.filters.maxValue) {
              return false
            }
            return true
          })
          .map(item => ({
            ...item,
            processedValue: item.value * 2 + 10
          }))
          .sort((a, b) => b.processedValue - a.processedValue)
      })
    },
    
    // 带参数的缓存getter
    getCachedFilteredData: (state) => {
      return (minValue: number, maxValue: number, category: string | null) => {
        return computed(() => {
          return state.largeDataset.filter(item => {
            if (category && item.category !== category) return false
            if (item.value < minValue || item.value > maxValue) return false
            return true
          })
        })
      }
    },
    
    // 分页数据
    getPaginatedData: (state) => {
      return (page: number, pageSize: number) => {
        const start = (page - 1) * pageSize
        return state.largeDataset.slice(start, start + pageSize)
      }
    },
    
    // 统计信息(缓存)
    dataStatistics: (state) => {
      return computed(() => {
        const total = state.largeDataset.length
        const activeCount = state.largeDataset.filter(item => item.active).length
        const avgValue = state.largeDataset.reduce((sum, item) => sum + item.value, 0) / total
        const categories = [...new Set(state.largeDataset.map(item => item.category))]
        
        return {
          total,
          activeCount,
          avgValue,
          categories,
          activePercentage: total > 0 ? (activeCount / total) * 100 : 0
        }
      })
    }
  }
})

interface DataItem {
  id: string
  value: number
  category: string
  active: boolean
}

避免Getter中的副作用

typescript
export const usePureGettersStore = defineStore('pureGetters', {
  state: () => ({
    items: [] as Item[],
    lastAccessed: new Map<string, number>()
  }),
  
  getters: {
    // ✅ 好的实践:纯函数getter
    activeItems: (state) => {
      return state.items.filter(item => item.active)
    },
    
    // ✅ 好的实践:带参数的纯函数getter
    getItemsByCategory: (state) => {
      return (category: string) => {
        return state.items.filter(item => item.category === category)
      }
    },
    
    // ❌ 避免:有副作用的getter
    // updateLastAccessed: (state) => {
    //   // 这是错误的,getter不应该修改状态
    //   state.lastAccessed.set('someKey', Date.now())
    //   return state.items
    // },
    
    // ✅ 正确方式:通过action更新状态
    itemsWithAccessTime: (state) => {
      return state.items.map(item => ({
        ...item,
        lastAccessed: state.lastAccessed.get(item.id) || null
      }))
    }
  },
  
  actions: {
    // 在action中更新访问时间
    recordAccess(itemId: string) {
      this.lastAccessed.set(itemId, Date.now())
    },
    
    addItem(item: Item) {
      this.items.push(item)
      this.recordAccess(item.id)
    }
  }
})

interface Item {
  id: string
  name: string
  category: string
  active: boolean
}

Getter与组件的深度集成

在组件中使用多个Store的Getters

vue
<template>
  <div class="dashboard">
    <div class="stats">
      <h3>System Statistics</h3>
      <p>Total Users: {{ userStore.users.length }}</p>
      <p>Active Sessions: {{ sessionStore.activeSessionsCount }}</p>
      <p>Pending Tasks: {{ taskStore.pendingTasksCount }}</p>
      <p>System Load: {{ systemStore.normalizedLoad }}</p>
    </div>
    
    <div class="user-list">
      <h3>Active Users</h3>
      <ul>
        <li 
          v-for="user in filteredActiveUsers" 
          :key="user.id"
          :class="{ premium: user.isPremium }"
        >
          <span>{{ user.name }}</span>
          <span class="role">{{ user.role }}</span>
          <span class="status">{{ user.status }}</span>
        </li>
      </ul>
    </div>
    
    <div class="performance">
      <h3>Performance Metrics</h3>
      <div class="metric" v-for="metric in performanceMetrics" :key="metric.name">
        <span class="name">{{ metric.name }}</span>
        <span class="value">{{ metric.value }}</span>
        <div class="trend" :class="metric.trend">
          {{ metric.trend }}
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed } from 'vue'
import { useUserStore } from '@/stores/user'
import { useSessionStore } from '@/stores/session'
import { useTaskStore } from '@/stores/task'
import { useSystemStore } from '@/stores/system'

const userStore = useUserStore()
const sessionStore = useSessionStore()
const taskStore = useTaskStore()
const systemStore = useSystemStore()

// 组合多个store的getters
const filteredActiveUsers = computed(() => {
  return userStore.users
    .filter(user => user.status === 'active')
    .sort((a, b) => b.lastLogin - a.lastLogin)
    .slice(0, 10) // 只显示最近活跃的10个用户
})

// 计算性能指标
const performanceMetrics = computed(() => [
  { 
    name: 'Response Time', 
    value: systemStore.avgResponseTime, 
    trend: systemStore.responseTimeTrend 
  },
  { 
    name: 'Error Rate', 
    value: systemStore.errorRate, 
    trend: systemStore.errorRateTrend 
  },
  { 
    name: 'Throughput', 
    value: systemStore.requestsPerSecond, 
    trend: systemStore.throughputTrend 
  }
])
</script>

<style scoped>
.dashboard {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  padding: 20px;
}

.stats {
  grid-column: 1 / -1;
  background: #f5f5f5;
  padding: 15px;
  border-radius: 8px;
}

.user-list ul {
  list-style: none;
  padding: 0;
}

.user-list li {
  display: flex;
  justify-content: space-between;
  padding: 8px;
  border-bottom: 1px solid #eee;
}

.user-list li.premium {
  background-color: #fffde7;
}

.metric {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 5px 0;
}

.trend {
  font-weight: bold;
}

.trend.up {
  color: green;
}

.trend.down {
  color: red;
}
</style>

Getter中的错误处理

typescript
export const useSafeGettersStore = defineStore('safeGetters', {
  state: () => ({
    data: null as Data[] | null,
    loading: false,
    error: null as string | null
  }),
  
  getters: {
    // 安全的数据访问
    safeData: (state) => {
      if (state.error) {
        console.warn('Error in safeData getter:', state.error)
        return []
      }
      return state.data || []
    },
    
    // 带默认值的数据访问
    processedData: (state) => {
      try {
        if (!state.data) return []
        
        return state.data.map(item => ({
          ...item,
          processed: true,
          timestamp: Date.now()
        }))
      } catch (error) {
        console.error('Error processing data:', error)
        return []
      }
    },
    
    // 统计信息(安全)
    dataStats: (state) => {
      try {
        const data = state.data || []
        return {
          count: data.length,
          avgValue: data.length > 0 
            ? data.reduce((sum, item) => sum + (item.value || 0), 0) / data.length 
            : 0,
          hasData: data.length > 0
        }
      } catch (error) {
        console.error('Error calculating stats:', error)
        return {
          count: 0,
          avgValue: 0,
          hasData: false
        }
      }
    },
    
    // 验证数据完整性
    isValidData: (state) => {
      try {
        if (!state.data) return false
        
        // 验证数据结构
        return state.data.every(item => 
          typeof item.id === 'string' && 
          typeof item.name === 'string'
        )
      } catch (error) {
        console.error('Error validating data:', error)
        return false
      }
    }
  },
  
  actions: {
    async loadData() {
      this.loading = true
      this.error = null
      
      try {
        const response = await fetch('/api/data')
        if (!response.ok) throw new Error('Failed to load data')
        
        this.data = await response.json()
      } catch (error) {
        this.error = (error as Error).message
        console.error('Load data error:', error)
      } finally {
        this.loading = false
      }
    }
  }
})

interface Data {
  id: string
  name: string
  value?: number
}

Getter最佳实践

1. Getter命名约定

typescript
export const useNamingStore = defineStore('naming', {
  state: () => ({
    users: [] as User[],
    settings: {
      theme: 'light',
      notifications: true
    }
  }),
  
  getters: {
    // ✅ 好的命名:描述性、以动词或形容词开头
    activeUsers: (state) => state.users.filter(user => user.active),
    userCount: (state) => state.users.length,
    hasUsers: (state) => state.users.length > 0,
    adminUsers: (state) => state.users.filter(user => user.role === 'admin'),
    
    // ✅ 带参数的getter:使用动词形式
    getUsersByRole: (state) => {
      return (role: string) => state.users.filter(user => user.role === role)
    },
    
    // ❌ 避免:不清晰的命名
    // u: (state) => state.users,  // 不好
    // calc: (state) => ...,       // 不好
  }
})

2. Getter组合

typescript
export const useComposedGettersStore = defineStore('composedGetters', {
  state: () => ({
    products: [] as Product[],
    cart: [] as CartItem[],
    user: null as User | null
  }),
  
  getters: {
    // 基础getter
    productMap: (state) => {
      return new Map(state.products.map(p => [p.id, p]))
    },
    
    // 组合getter
    cartTotal: (state) => {
      return state.cart.reduce((total, item) => {
        const product = this.productMap.get(item.productId)
        return total + (product ? product.price * item.quantity : 0)
      }, 0)
    },
    
    // 复杂组合
    cartItemsWithDetails: (state) => {
      return state.cart.map(item => {
        const product = this.productMap.get(item.productId)
        return {
          ...item,
          product: product || null,
          subtotal: product ? product.price * item.quantity : 0
        }
      })
    },
    
    // 条件组合
    checkoutEnabled: (state) => {
      return this.cartTotal > 0 && !!state.user && state.user.verified
    }
  }
})

interface Product {
  id: string
  name: string
  price: number
}

interface CartItem {
  productId: string
  quantity: number
}

interface User {
  id: string
  email: string
  verified: boolean
}

3. 类型安全的Getters

typescript
import { StoreGeneric, storeToRefs } from 'pinia'

export const useTypedGettersStore = defineStore('typedGetters', {
  state: () => ({
    posts: [] as Post[],
    authors: new Map<string, Author>(),
    currentUserId: null as string | null
  }),
  
  getters: {
    // 明确的返回类型
    publishedPosts: (state): Post[] => {
      return state.posts.filter(post => post.status === 'published')
    },
    
    myPosts: (state): Post[] => {
      if (!state.currentUserId) return []
      return state.posts.filter(post => post.authorId === state.currentUserId)
    },
    
    // 复杂类型的getter
    postsWithAuthorInfo: (state): PostWithAuthor[] => {
      return state.posts.map(post => {
        const author = state.authors.get(post.authorId)
        return {
          ...post,
          author: author || null
        }
      })
    },
    
    // 带参数的类型化getter
    getPostsByAuthor: (state) => {
      return (authorId: string): Post[] => {
        return state.posts.filter(post => post.authorId === authorId)
      }
    }
  }
})

interface Post {
  id: string
  title: string
  content: string
  authorId: string
  status: 'draft' | 'published' | 'archived'
}

interface Author {
  id: string
  name: string
  email: string
}

interface PostWithAuthor extends Post {
  author: Author | null
}

总结

Getters是Pinia中强大的计算属性机制,通过本章的学习,你应该掌握:

  1. 基础Getters:定义和使用简单的计算属性
  2. 带参数的Getters:创建灵活的过滤和搜索功能
  3. 复杂逻辑Getters:实现统计、聚合和转换
  4. 性能优化:使用computed缓存和避免副作用
  5. 错误处理:在Getters中安全地处理异常
  6. 最佳实践:命名约定、组合和类型安全

Getters使我们能够以声明式的方式从状态派生数据,同时自动处理依赖追踪和缓存,是构建响应式应用的重要工具。