Vuex 的 TypeScript 深度集成指南

TypeScript 为 Vuex 带来了强大的类型支持,让状态管理更加安全和可维护。本文将深入探讨 Vuex 的类型化实践。

一、核心概念的类型化

1. 类型化 State

interface UserState {
  id: number
  name: string
  roles: string[]
}

const state: UserState = {
  id: 0,
  name: '',
  roles: []
}

实践建议

  • 为每个模块定义独立的状态接口
  • 使用 readonly 修饰符防止直接修改

2. 类型化 Getters

const getters = {
  fullName: (state: UserState) => `${state.firstName} ${state.lastName}`,
  hasPermission: (state: UserState) => (role: string) => state.roles.includes(role)
} as GetterTree<UserState, RootState>

3. 类型化 Mutations

const mutations = {
  SET_USER(state: UserState, payload: { id: number; name: string }) {
    state.id = payload.id
    state.name = payload.name
  }
} as MutationTree<UserState>

关键点

  • 使用 MutationTree 类型包装
  • payload 应该明确定义类型

4. 类型化 Actions

const actions = {
  async fetchUser({ commit }, userId: number) {
    const user = await api.fetchUser(userId)
    commit('SET_USER', user)
  }
} as ActionTree<UserState, RootState>

二、模块与命名空间

1. 模块类型定义

import { Module } from 'vuex'

const userModule: Module<UserState, RootState> = {
  namespaced: true,
  state,
  getters,
  mutations,
  actions
}

2. 命名空间访问

// 在组件中使用
this.$store.dispatch('user/fetchUser', 123)

类型安全建议

// 定义类型化的 dispatch
type UserActions = {
  fetchUser(userId: number): Promise<void>
}

// 组件中使用
this.$store.dispatch('user/fetchUser', 123) // 自动检查参数类型

三、类型安全的工具函数

1. 类型化 mapState

import { createNamespacedHelpers } from 'vuex'

const { mapState } = createNamespacedHelpers('user')

export default {
  computed: {
    ...mapState(['name', 'roles']), // 自动推断类型
    ...mapState({
      userName: state => state.name // 带转换函数的类型推断
    })
  }
}

2. 类型化 mapActions

const { mapActions } = createNamespacedHelpers('user')

export default {
  methods: {
    ...mapActions(['fetchUser']), // 自动推断参数类型
    async loadUser() {
      await this.fetchUser(123) // 类型检查
    }
  }
}

四、完整类型定义示例

// store/types.ts
export interface RootState {
  version: string
}

export interface UserState {
  id: number
  name: string
  roles: string[]
}

// store/modules/user/actions.ts
export interface UserActions {
  fetchUser(userId: number): Promise<void>
  updateProfile(payload: { name: string }): Promise<boolean>
}

// 在组件中使用
import { UserActions } from '@/store/modules/user/actions'

@Component
export default class UserProfile extends Vue {
  @Action('user/fetchUser') 
  fetchUser!: UserActions['fetchUser'] // 精确的类型绑定
}

五、最佳实践建议

  1. 分层类型定义

    • 将状态接口与模块定义分离
    • 为复杂 payload 定义专用类型
  2. 类型复用

    // 共享类型定义
    export type User = {
      id: number
      name: string
    }
    
    // 在状态和API中复用
    interface UserState {
      current: User | null
    }
  3. 严格模式配置

    import { createStore } from 'vuex'
    
    export default createStore({
      strict: process.env.NODE_ENV !== 'production',
      // ...其他配置
    })
  4. 类型检查工具

    // tsconfig.json
    {
      "compilerOptions": {
        "strict": true,
        "noImplicitAny": true
      }
    }

通过以上类型化实践,可以显著提高 Vuex 代码的可靠性和开发体验,减少运行时错误,增强代码的可维护性。

评论已关闭