Appearance
Pinia TypeScript集成
Pinia与TypeScript的集成非常优秀,提供了完整的类型安全支持。本章将详细介绍如何在Pinia中充分利用TypeScript的类型系统,确保状态管理的类型安全和开发体验。
TypeScript基础集成
基础类型定义
typescript
import { defineStore } from 'pinia'
// 定义类型接口
interface User {
id: string
name: string
email: string
role: 'admin' | 'user' | 'moderator'
createdAt: Date
}
interface Preferences {
theme: 'light' | 'dark'
language: string
notifications: boolean
}
// 定义Store状态类型
interface UserState {
currentUser: User | null
preferences: Preferences
loading: boolean
error: string | null
}
// 定义Store
export const useUserStore = defineStore('user', {
// 状态定义 - TypeScript会自动推断类型
state: (): UserState => ({
currentUser: null,
preferences: {
theme: 'light',
language: 'en',
notifications: true
},
loading: false,
error: null
}),
// Getter类型定义
getters: {
// 自动推断返回类型
isAuthenticated: (state): boolean => state.currentUser !== null,
// 复杂计算类型的getter
userProfile: (state): (Pick<User, 'id' | 'name' | 'email'> & { isOnline: boolean }) | null => {
if (!state.currentUser) return null
return {
id: state.currentUser.id,
name: state.currentUser.name,
email: state.currentUser.email,
isOnline: true // 简化的在线状态
}
},
// 带参数的getter - 返回函数
getUserById: (state) => {
return (id: string): User | undefined => {
// 这里需要扩展状态以包含用户列表
return state.currentUser?.id === id ? state.currentUser : undefined
}
}
},
// Action类型定义
actions: {
// 同步action
setCurrentUser(user: User) {
this.currentUser = user
this.error = null
},
// 异步action
async login(credentials: { email: string; password: string }): Promise<void> {
this.loading = true
this.error = null
try {
// 模拟API调用
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
})
if (!response.ok) throw new Error('Login failed')
const userData: User = await response.json()
this.setCurrentUser(userData)
} catch (error) {
this.error = (error as Error).message
throw error
} finally {
this.loading = false
}
},
// 更新偏好设置
async updatePreferences(updates: Partial<Preferences>) {
this.preferences = { ...this.preferences, ...updates }
// 保存到后端
try {
await fetch('/api/preferences', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(this.preferences)
})
} catch (error) {
console.error('Failed to update preferences:', error)
// 恢复到之前的设置
this.preferences = { ...this.preferences, ...updates }
}
},
// 登出
logout() {
this.currentUser = null
this.loading = false
this.error = null
}
}
})
在组件中使用类型安全的Store
vue
<template>
<div class="user-profile">
<div v-if="userStore.loading" class="loading">
Loading...
</div>
<div v-else-if="userStore.error" class="error">
{{ userStore.error }}
</div>
<div v-else-if="userStore.isAuthenticated" class="profile">
<h2>Welcome, {{ userStore.currentUser?.name }}!</h2>
<p>Email: {{ userStore.currentUser?.email }}</p>
<p>Role: {{ userStore.currentUser?.role }}</p>
<div class="preferences">
<h3>Preferences</h3>
<div>
<label>
Theme:
<select
:value="userStore.preferences.theme"
@change="handleThemeChange"
>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</label>
</div>
<div>
<label>
Language:
<input
type="text"
:value="userStore.preferences.language"
@input="handleLanguageChange"
/>
</label>
</div>
<div>
<label>
<input
type="checkbox"
:checked="userStore.preferences.notifications"
@change="handleNotificationToggle"
/>
Enable Notifications
</label>
</div>
</div>
<button @click="userStore.logout()" class="logout-btn">
Logout
</button>
</div>
<div v-else class="login">
<h2>Login</h2>
<form @submit.prevent="handleLogin">
<div>
<input
v-model="loginForm.email"
type="email"
placeholder="Email"
required
/>
</div>
<div>
<input
v-model="loginForm.password"
type="password"
placeholder="Password"
required
/>
</div>
<button type="submit" :disabled="userStore.loading">
{{ userStore.loading ? 'Logging in...' : 'Login' }}
</button>
</form>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useUserStore, type User } from '@/stores/user'
// 类型化的Store实例
const userStore = useUserStore()
// 类型化的表单数据
const loginForm = reactive({
email: '',
password: ''
})
// 类型化的事件处理器
const handleLogin = async () => {
try {
await userStore.login(loginForm)
// 登录成功后的处理
console.log('Login successful', userStore.currentUser)
} catch (error) {
console.error('Login failed:', error)
}
}
const handleThemeChange = (event: Event) => {
const target = event.target as HTMLSelectElement
userStore.updatePreferences({ theme: target.value as 'light' | 'dark' })
}
const handleLanguageChange = (event: Event) => {
const target = event.target as HTMLInputElement
userStore.updatePreferences({ language: target.value })
}
const handleNotificationToggle = (event: Event) => {
const target = event.target as HTMLInputElement
userStore.updatePreferences({ notifications: target.checked })
}
</script>
<style scoped>
.user-profile {
max-width: 600px;
margin: 0 auto;
padding: 2rem;
}
.loading, .error {
text-align: center;
padding: 2rem;
}
.error {
color: #d32f2f;
}
.profile, .login {
border: 1px solid #ddd;
border-radius: 8px;
padding: 2rem;
}
.preferences {
margin: 2rem 0;
padding: 1rem;
background-color: #f5f5f5;
border-radius: 4px;
}
.preferences div {
margin-bottom: 1rem;
}
.logout-btn {
background-color: #f44336;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
}
</style>
高级类型模式
泛型Store定义
typescript
// stores/generic.ts
export interface Identifiable {
id: string
}
export interface Timestamped {
createdAt: Date
updatedAt: Date
}
// 泛型Store定义
export function createEntityStore<T extends Identifiable & Timestamped>(
storeId: string,
initialState: T[] = []
) {
return defineStore(storeId, {
state: () => ({
entities: [] as T[],
loading: false,
error: null as string | null,
selectedId: null as string | null
}),
getters: {
// 根据ID获取实体
getById: (state) => {
return (id: string): T | undefined => {
return state.entities.find(entity => entity.id === id)
}
},
// 获取所有实体
allEntities: (state): readonly T[] => state.entities,
// 获取选中的实体
selectedEntity: (state): T | null => {
if (!state.selectedId) return null
return state.entities.find(entity => entity.id === state.selectedId) || null
},
// 实体数量
count: (state): number => state.entities.length,
// 是否为空
isEmpty: (state): boolean => state.entities.length === 0
},
actions: {
// 添加实体
addEntity(entity: T) {
// 检查是否已存在
const existingIndex = this.entities.findIndex(e => e.id === entity.id)
if (existingIndex !== -1) {
this.entities[existingIndex] = { ...this.entities[existingIndex], ...entity }
} else {
this.entities.push(entity)
}
},
// 更新实体
updateEntity(id: string, updates: Partial<T>) {
const index = this.entities.findIndex(entity => entity.id === id)
if (index !== -1) {
this.entities[index] = { ...this.entities[index], ...updates } as T
}
},
// 删除实体
removeEntity(id: string) {
this.entities = this.entities.filter(entity => entity.id !== id)
if (this.selectedId === id) {
this.selectedId = null
}
},
// 选择实体
selectEntity(id: string) {
this.selectedId = id
},
// 清除选择
clearSelection() {
this.selectedId = null
},
// 批量添加实体
addMultiple(entities: T[]) {
entities.forEach(entity => this.addEntity(entity))
},
// 设置所有实体
setAll(entities: T[]) {
this.entities = [...entities]
},
// 异步加载实体
async fetchEntities(fetcher: () => Promise<T[]>) {
this.loading = true
this.error = null
try {
const entities = await fetcher()
this.setAll(entities)
} catch (error) {
this.error = (error as Error).message
throw error
} finally {
this.loading = false
}
}
}
})
}
// 使用泛型Store
interface Product extends Identifiable, Timestamped {
name: string
price: number
category: string
inStock: boolean
}
interface Order extends Identifiable, Timestamped {
userId: string
items: OrderItem[]
total: number
status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled'
}
interface OrderItem {
productId: string
quantity: number
price: number
}
// 创建具体的Store实例
export const useProductStore = createEntityStore<Product>('products')
export const useOrderStore = createEntityStore<Order>('orders')
条件类型和高级类型操作
typescript
// types/conditional.ts
// 条件类型 - 根据某个属性的存在来决定类型
type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
type WithRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
// 工具类型 - 提取Store的State类型
type StoreState<TStore> = TStore extends { $state: infer TState } ? TState : never
// 工具类型 - 提取Store的Getters类型
type StoreGetters<TStore> = TStore extends {
[K: string]: any;
$state: any
} ? Pick<TStore, { [K in keyof TStore]: TStore[K] extends Function ? never : K }[keyof TStore]> : never
// 工具类型 - 提取Store的Actions类型
type StoreActions<TStore> = TStore extends {
[K: string]: infer TValue
} ? { [K in keyof TStore as TValue extends Function ? K : never]: TValue } : never
// 创建类型安全的Store工厂
interface StoreConfig<State, Getters, Actions> {
state: () => State
getters?: Getters
actions?: Actions
}
// 类型化的Store创建函数
function createTypedStore<
S extends Record<string, any>,
G extends Record<string, any>,
A extends Record<string, any>
>(
id: string,
config: {
state: () => S
getters?: G
actions?: A
}
) {
return defineStore(id, {
state: config.state,
getters: config.getters || {},
actions: config.actions || {}
}) as () => {
$state: S
} & S & G & A
}
// 使用示例
interface CartItem {
id: string
name: string
price: number
quantity: number
}
interface CartState {
items: CartItem[]
discount: number
shipping: number
}
interface CartGetters {
readonly total: number
readonly itemCount: number
readonly discountedTotal: number
}
interface CartActions {
addItem(item: Omit<CartItem, 'quantity'>): void
removeItem(id: string): void
updateQuantity(id: string, quantity: number): void
applyDiscount(percent: number): void
clearCart(): void
}
export const useCartStore = createTypedStore<CartState, CartGetters, CartActions>('cart', {
state: () => ({
items: [],
discount: 0,
shipping: 0
}),
getters: {
get total() {
return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0)
},
get itemCount() {
return this.items.reduce((count, item) => count + item.quantity, 0)
},
get discountedTotal() {
return Math.max(0, (this.total - this.discount) + this.shipping)
}
},
actions: {
addItem(item) {
const existingItem = this.items.find(i => i.id === item.id)
if (existingItem) {
existingItem.quantity += 1
} else {
this.items.push({ ...item, quantity: 1 })
}
},
removeItem(id) {
this.items = this.items.filter(item => item.id !== id)
},
updateQuantity(id, quantity) {
if (quantity <= 0) {
this.removeItem(id)
return
}
const item = this.items.find(i => i.id === id)
if (item) {
item.quantity = quantity
}
},
applyDiscount(percent) {
this.discount = Math.min(this.total * (percent / 100), this.total)
},
clearCart() {
this.items = []
this.discount = 0
}
}
})
类型安全的Store模式
Store组合类型
typescript
// stores/composables.ts
import { computed, ComputedRef } from 'vue'
import { storeToRefs } from 'pinia'
// 类型安全的storeToRefs增强版
export function typedStoreToRefs<TStore>(store: TStore) {
const refs = storeToRefs(store)
return refs as {
[K in keyof TStore as TStore[K] extends ComputedRef<any> ? K : never]: TStore[K]
}
}
// Store选择器类型
type Selector<TState, TResult> = (state: TState) => TResult
export function createSelector<TState, TResult>(
selector: Selector<TState, TResult>
): Selector<TState, TResult> {
return selector
}
// 带类型安全的选择器Hook
export function useStoreSelector<TStore, TResult>(
store: TStore,
selector: (state: TStore extends { $state: infer TState } ? TState : never) => TResult
): ComputedRef<TResult> {
return computed(() => selector(store.$state))
}
// 使用示例
interface User {
id: string
name: string
email: string
role: string
}
interface AppState {
user: User | null
theme: 'light' | 'dark'
language: string
}
export const useAppStore = defineStore('app', {
state: (): AppState => ({
user: null,
theme: 'light',
language: 'en'
}),
getters: {
isLoggedIn: (state) => state.user !== null,
userName: (state) => state.user?.name || 'Guest',
userEmail: (state) => state.user?.email
},
actions: {
setUser(user: User) {
this.user = user
},
setTheme(theme: 'light' | 'dark') {
this.theme = theme
},
setLanguage(language: string) {
this.language = language
}
}
})
// 在组件中使用类型安全的选择器
import { useAppStore } from '@/stores/app'
// 组件中使用
const appStore = useAppStore()
// 类型安全的状态引用
const { user, theme, language } = typedStoreToRefs(appStore)
// 类型安全的选择器
const userDisplayName = useStoreSelector(
appStore,
(state) => state.user ? `${state.user.name} (${state.user.email})` : 'Guest'
)
const isLoggedIn = useStoreSelector(
appStore,
(state) => state.user !== null
)
类型化的Store中间件
typescript
// stores/middlewares.ts
interface MiddlewareContext<State, Getters, Actions> {
state: State
getters: Getters
actions: Actions
next: (payload: any) => any
}
type Middleware<State, Getters, Actions> = (
context: MiddlewareContext<State, Getters, Actions>
) => any
// 类型安全的Store增强器
export function createStoreEnhancer<S, G, A>(
storeFactory: () => any,
middlewares: Middleware<S, G, A>[] = []
) {
return () => {
const store = storeFactory()
// 应用中间件
middlewares.forEach(middleware => {
middleware({
state: store.$state,
getters: store,
actions: store,
next: (payload) => payload
})
})
return store
}
}
// 日志中间件类型定义
interface LogMiddlewareConfig {
logActions?: boolean
logMutations?: boolean
filter?: (mutation: any) => boolean
}
export function createLogMiddleware<S, G, A>(config: LogMiddlewareConfig = {}) {
const { logActions = true, logMutations = true, filter } = config
return (context: MiddlewareContext<S, G, A>) => {
// 如果需要,可以在这里拦截和处理store行为
return context.next(context)
}
}
// 持久化中间件
interface PersistenceMiddlewareConfig {
key: string
storage?: Storage
}
export function createPersistenceMiddleware<S>(config: PersistenceMiddlewareConfig) {
const { key, storage = localStorage } = config
return (context: MiddlewareContext<S, any, any>) => {
// 恢复状态
const savedState = storage.getItem(key)
if (savedState) {
try {
const parsedState = JSON.parse(savedState)
// 这里需要根据具体实现来恢复状态
console.log('Restored state from', key)
} catch (error) {
console.error('Failed to restore state:', error)
}
}
// 监听状态变化并保存
const unsubscribe = context.actions.$subscribe((mutation, state) => {
try {
storage.setItem(key, JSON.stringify(state))
} catch (error) {
console.error('Failed to persist state:', error)
}
})
// 返回清理函数
return () => unsubscribe()
}
}
类型推断优化
智能类型推断
typescript
// stores/inference.ts
// 使用映射类型来自动推断getter类型
type GetterDefinitions<State> = {
[K: string]: (state: State) => any
}
type InferGetters<G extends GetterDefinitions<any>> = {
[K in keyof G]: G[K] extends (state: any) => infer R ? R : never
}
// 使用条件类型来区分同步和异步actions
type SyncAction = (...args: any[]) => any
type AsyncAction = (...args: any[]) => Promise<any>
type ActionDefinitions = {
[K: string]: SyncAction | AsyncAction
}
type InferActions<A extends ActionDefinitions> = {
[K in keyof A]: A[K]
}
// 高级类型推断示例
interface Todo {
id: string
text: string
completed: boolean
createdAt: Date
}
interface TodoFilters {
status: 'all' | 'active' | 'completed'
search: string
}
// 完整的Todo Store类型定义
interface TodoStoreState {
todos: Todo[]
filters: TodoFilters
loading: boolean
error: string | null
}
interface TodoStoreGetters {
readonly filteredTodos: Todo[]
readonly activeCount: number
readonly completedCount: number
readonly allCompleted: boolean
getTodoById: (id: string) => Todo | undefined
}
interface TodoStoreActions {
addTodo(text: string): void
removeTodo(id: string): void
toggleTodo(id: string): void
setFilter(filter: Partial<TodoFilters>): void
clearCompleted(): void
fetchTodos(): Promise<void>
updateTodo(id: string, updates: Partial<Todo>): void
}
// 使用类型推断创建Store
export const useTodoStore = defineStore('todos', {
state: (): TodoStoreState => ({
todos: [],
filters: {
status: 'all',
search: ''
},
loading: false,
error: null
}),
getters: {
// TypeScript会自动推断返回类型
filteredTodos: (state) => {
let result = state.todos
// 根据状态过滤
if (state.filters.status === 'active') {
result = result.filter(todo => !todo.completed)
} else if (state.filters.status === 'completed') {
result = result.filter(todo => todo.completed)
}
// 根据搜索词过滤
if (state.filters.search) {
const searchLower = state.filters.search.toLowerCase()
result = result.filter(todo =>
todo.text.toLowerCase().includes(searchLower)
)
}
return result
},
activeCount: (state) => state.todos.filter(todo => !todo.completed).length,
completedCount: (state) => state.todos.filter(todo => todo.completed).length,
allCompleted: (state) => state.todos.length > 0 &&
state.todos.every(todo => todo.completed),
getTodoById: (state) => {
return (id: string) => state.todos.find(todo => todo.id === id)
}
},
actions: {
addTodo(text: string) {
if (!text.trim()) return
const newTodo: Todo = {
id: Date.now().toString(),
text: text.trim(),
completed: false,
createdAt: new Date()
}
this.todos.push(newTodo)
},
removeTodo(id: string) {
this.todos = this.todos.filter(todo => todo.id !== id)
},
toggleTodo(id: string) {
const todo = this.todos.find(t => t.id === id)
if (todo) {
todo.completed = !todo.completed
}
},
setFilter(filter: Partial<TodoFilters>) {
this.filters = { ...this.filters, ...filter }
},
clearCompleted() {
this.todos = this.todos.filter(todo => !todo.completed)
},
async fetchTodos() {
this.loading = true
this.error = null
try {
const response = await fetch('/api/todos')
if (!response.ok) throw new Error('Failed to fetch todos')
const todos: Todo[] = await response.json()
this.todos = todos
} catch (error) {
this.error = (error as Error).message
throw error
} finally {
this.loading = false
}
},
updateTodo(id: string, updates: Partial<Todo>) {
const todoIndex = this.todos.findIndex(t => t.id === id)
if (todoIndex !== -1) {
this.todos[todoIndex] = { ...this.todos[todoIndex], ...updates }
}
}
}
}) satisfies () => {
$state: TodoStoreState
} & TodoStoreState & TodoStoreGetters & TodoStoreActions
类型安全的Store测试
类型化的测试辅助函数
typescript
// __tests__/typescript.spec.ts
import { setActivePinia, createPinia } from 'pinia'
import { useUserStore, type User } from '@/stores/user'
import { useTodoStore } from '@/stores/inference'
import { vi, describe, it, beforeEach, expect } from 'vitest'
describe('TypeScript Integration Tests', () => {
beforeEach(() => {
setActivePinia(createPinia())
})
it('should provide full type safety for user store', () => {
const userStore = useUserStore()
// 状态类型检查
expect(typeof userStore.loading).toBe('boolean')
expect(userStore.error).toBeNull()
// Action参数类型检查
const mockUser: User = {
id: '1',
name: 'John Doe',
email: 'john@example.com',
role: 'user',
createdAt: new Date()
}
userStore.setCurrentUser(mockUser)
// Getter返回类型检查
expect(userStore.isAuthenticated).toBe(true)
expect(userStore.currentUser?.name).toBe('John Doe')
// 类型安全的action调用
userStore.updatePreferences({ theme: 'dark' })
expect(userStore.preferences.theme).toBe('dark')
})
it('should maintain type safety in todo store', () => {
const todoStore = useTodoStore()
// 状态类型检查
expect(Array.isArray(todoStore.todos)).toBe(true)
expect(typeof todoStore.loading).toBe('boolean')
// Action调用类型检查
todoStore.addTodo('Test todo')
// Getter类型检查
expect(todoStore.activeCount).toBe(1)
expect(todoStore.allCompleted).toBe(false)
// 带参数的getter类型检查
const todo = todoStore.getTodoById(todoStore.todos[0].id)
expect(todo).toBeDefined()
expect(todo?.text).toBe('Test todo')
})
it('should handle async actions with proper typing', async () => {
const userStore = useUserStore()
// Mock fetch
global.fetch = vi.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({
id: '1',
name: 'Jane Doe',
email: 'jane@example.com',
role: 'admin',
createdAt: new Date()
})
} as Response)
) as any
// 类型安全的异步action调用
await expect(userStore.login({
email: 'jane@example.com',
password: 'password'
})).resolves.not.toThrow()
expect(userStore.currentUser?.name).toBe('Jane Doe')
expect(userStore.isAuthenticated).toBe(true)
})
it('should enforce type safety for partial updates', () => {
const userStore = useUserStore()
const mockUser: User = {
id: '1',
name: 'John Doe',
email: 'john@example.com',
role: 'user',
createdAt: new Date()
}
userStore.setCurrentUser(mockUser)
// 类型安全的属性访问
const name = userStore.currentUser?.name
expect(name).toBe('John Doe')
// 类型安全的可选链
const nonExistent = userStore.currentUser?.nonExistentProperty
// 这应该是undefined,TypeScript会正确识别
// 类型安全的partial更新
userStore.updatePreferences({
theme: 'dark', // 正确的枚举值
// notifications: true // 可选属性
// language不会被要求,因为它有默认值
})
})
})
// 类型测试 - 确保类型定义正确
describe('Type Definitions', () => {
it('should enforce correct types at compile time', () => {
const userStore = useUserStore()
// 以下代码应该在TypeScript检查中报错:
// userStore.updatePreferences({ theme: 'invalid_theme' }) // 错误:不是有效主题
// userStore.currentUser = {} // 错误:缺少必需属性
// 正确的类型使用
userStore.updatePreferences({ theme: 'dark' })
userStore.setCurrentUser({
id: '1',
name: 'Test User',
email: 'test@example.com',
role: 'user',
createdAt: new Date()
})
expect(userStore.currentUser?.role).toBe('user')
})
})
高级类型技巧
条件类型和分布式条件类型
typescript
// types/advanced.ts
// 提取所有函数类型的键
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? K : never
}[keyof T]
// 提取所有非函数类型的键
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K
}[keyof T]
// 分离函数和非函数属性
type Functions<T> = Pick<T, FunctionPropertyNames<T>>
type NonFunctions<T> = Pick<T, NonFunctionPropertyNames<T>>
// 在Store中使用
interface AdvancedStoreState {
count: number
name: string
items: string[]
}
interface AdvancedStoreActions {
increment(): void
decrement(): void
setName(name: string): void
addItem(item: string): void
reset(): void
}
interface AdvancedStoreGetters {
doubleCount: number
hasItems: boolean
upperCaseName: string
}
// 完整的Store类型
type AdvancedStoreType = AdvancedStoreState & AdvancedStoreActions & AdvancedStoreGetters
// 提取各部分
type StateProps = NonFunctions<AdvancedStoreType>
type ActionProps = Functions<AdvancedStoreType>
// 高级类型操作
type MakeOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
type MakeRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
// 创建类型安全的Store配置
interface StoreConfigBase<S, G, A> {
state: () => S
getters?: G
actions?: A
}
// 类型安全的Store创建器
function createStrictStore<S, G, A>(id: string, config: StoreConfigBase<S, G, A>) {
return defineStore(id, config) as () => S & G & A
}
// 使用示例
export const useAdvancedStore = createStrictStore<
AdvancedStoreState,
AdvancedStoreGetters,
AdvancedStoreActions
>('advanced', {
state: () => ({
count: 0,
name: '',
items: []
}),
getters: {
get doubleCount() {
return this.count * 2
},
get hasItems() {
return this.items.length > 0
},
get upperCaseName() {
return this.name.toUpperCase()
}
},
actions: {
increment() {
this.count++
},
decrement() {
this.count--
},
setName(name: string) {
this.name = name
},
addItem(item: string) {
this.items.push(item)
},
reset() {
this.count = 0
this.name = ''
this.items = []
}
}
})
总结
Pinia与TypeScript的集成提供了完整的类型安全,通过本章的学习,你应该掌握:
- 基础类型集成:如何为Store定义完整的类型
- 高级类型模式:泛型Store、条件类型等高级技巧
- 类型安全模式:Store组合、选择器等模式的类型化实现
- 类型推断优化:利用TypeScript的智能推断能力
- 测试类型安全:确保类型定义的正确性
- 高级类型技巧:分布式条件类型等高级特性
TypeScript的类型安全能够帮助我们在编译时发现潜在错误,提供更好的开发体验和代码可维护性。