pinia是vue 3最推荐的类型安全全局状态方案,原生支持ts自动推导state、getters、actions类型;vuex需手动声明接口和增强类型才能实现真正安全。

Vue 全局状态的类型安全,核心在于让状态定义、访问和更新全程受 TypeScript 类型约束,避免 any 泛滥、运行时取值错误或 IDE 补全失效。关键不在于堆砌配置,而在于选对方案、写对结构、补对声明。
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
Pinia 是当前 Vue 3 项目最推荐的类型安全全局状态方案
它原生支持 TypeScript,无需额外类型声明即可自动推导 state、getters、actions 的完整类型,且模块拆分后类型依然隔离清晰。相比 Vuex,Pinia 的类型体验更轻量、更稳定。
// src/stores/user.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
id: 0,
username: '' as string,
email: '' as string,
role: 'guest' as 'guest' | 'user' | 'admin'
}),
getters: {
isStaff: (state) => state.role !== 'guest',
displayName: (state) => state.username || 'Anonymous'
},
actions: {
login(payload: { email: string; password: string }) {
// payload 参数类型自动校验
this.email = payload.email
this.id = Math.floor(Math.random() * 1000)
},
logout() {
this.$reset() // 类型安全重置,字段不会遗漏
}
}
})
Vuex 需手动补全类型声明才能真正安全
如果你仍在维护 Vue 2 或迁移中的 Vuex 项目,必须为 Store 实例显式标注状态接口,并通过模块增强让 this.$store 可被识别:
// src/store/index.ts
import { Store } from 'vuex'
import { createStore } from 'vuex'
interface State {
count: number
token: string | null
userInfo: { name: string; avatar: string } | null
}
export const store = createStore<state>({
state: () => ({
count: 0,
token: null,
userInfo: null
}),
mutations: {
SET_TOKEN(state, token: string) {
state.token = token
}
}
})</state>
// src/types/vuex.d.ts
import { Store } from 'vuex'
import { State } from '@/store'
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$store: Store<state>
}
}</state>
Composition API 中使用 store 必须类型化 useStore
在 setup() 或 defineComponent 中调用 useStore() 时,TypeScript 默认返回 Store<any></any>。需配合泛型或自定义 hook 显式注入类型:
// src/composables/useTypedStore.ts
import { useStore as useRawStore } from 'vuex'
import type { Store } from 'vuex'
import type { State } from '@/store'
export function useStore() {
return useRawStore<state>() as Store<state>
}</state></state>
与 API 响应类型联动,避免状态和接口脱节
全局状态常承载后端数据。建议用 openapi-typescript 生成接口类型,再直接复用于 store:
// src/generated/api.d.ts(由 OpenAPI 自动生成)
export interface User {
id: number
name: string
email: string
}
// src/stores/user.ts
import { defineStore } from 'pinia'
import { User } from '@/generated/api'
export const useUserStore = defineStore('user', {
state: (): { data: User | null } => ({
data: null
}),
actions: {
async fetchProfile(id: number) {
const res = await fetch(`/api/users/${id}`)
const user: User = await res.json() // 类型已约束
this.data = user
}
}
})
组件中消费状态时,也要保持类型连贯
无论是 mapState 还是 useStore,最终读取的属性都应有明确类型提示:
<script setup lang="ts">
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
// userStore.data 自动推导为 User | null,.name 访问有补全、有校验
console.log(userStore.data?.name)
</script>
不复杂但容易忽略:类型安全不是一次配置就一劳永逸,而是从 store 定义 → API 类型 → 组件消费,每层都保持类型穿透。Pinia 天然支持这点;Vuex 则依赖你主动补全接口和声明文件。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










