面试题答案
一键面试1. 在Vuex的mutation中定义参数类型
- 常规状态修改的mutation:
- 首先,在定义Vuex的
state
时,明确其类型。例如,如果state
中有一个count
属性,假设它是number
类型:
// store.ts import { createStore } from 'vuex'; // 定义state类型 interface State { count: number; } const store = createStore<State>({ state: { count: 0 }, mutations: { increment(state) { state.count++; }, // 带参数的mutation setCount(state, payload: number) { state.count = payload; } } }); export default store;
- 这里,
increment
mutation没有参数,而setCount
mutation接收一个number
类型的payload
参数。在使用这些mutation时,TypeScript会进行类型检查,确保传递的参数类型正确。
- 首先,在定义Vuex的
- 复杂对象作为参数的mutation:
- 如果mutation接收一个复杂对象作为参数,最好先定义这个对象的类型。例如,假设要更新用户信息:
// 定义用户信息类型 interface UserInfo { name: string; age: number; } const store = createStore<State>({ state: { user: { name: '', age: 0 } as UserInfo }, mutations: { updateUser(state, payload: UserInfo) { state.user = payload; } } });
2. 在Vuex的action中定义参数类型
- 简单action:
- action通常会通过
context
对象来访问state
、commit
等。context
的类型可以从vuex
中导入。例如:
import { ActionContext } from 'vuex'; // 定义state类型 interface State { count: number; } const store = createStore<State>({ state: { count: 0 }, mutations: { increment(state) { state.count++; } }, actions: { // 简单action asyncIncrement(context: ActionContext<State, State>) { setTimeout(() => { context.commit('increment'); }, 1000); }, // 带参数的action asyncSetCount(context: ActionContext<State, State>, payload: number) { setTimeout(() => { context.commit('setCount', payload); }, 1000); } } });
- 这里
asyncIncrement
action没有额外参数,而asyncSetCount
action接收一个number
类型的payload
参数。ActionContext
的第一个泛型参数是当前模块的state
类型,第二个泛型参数是根state
类型(如果是模块,根state
类型可能不同)。
- action通常会通过
- 复杂参数的action:
- 类似于mutation,当action接收复杂参数时,先定义参数类型。例如,假设要通过API获取用户信息并更新到store:
import { ActionContext } from 'vuex'; // 定义用户信息类型 interface UserInfo { name: string; age: number; } // 模拟API调用 const getUserInfo = (): Promise<UserInfo> => { return new Promise((resolve) => { setTimeout(() => { resolve({ name: 'John', age: 30 }); }, 1000); }); }; const store = createStore<State>({ state: { user: { name: '', age: 0 } as UserInfo }, mutations: { updateUser(state, payload: UserInfo) { state.user = payload; } }, actions: { async fetchUser(context: ActionContext<State, State>) { const userInfo = await getUserInfo(); context.commit('updateUser', userInfo); } } });
3. 在Vue Router的导航守卫中进行类型检查
- 全局前置守卫:
- 在使用
router.beforeEach
进行全局前置守卫时,to
和from
参数都有特定类型。to
和from
是Route
类型,可以从vue-router
中导入。例如:
import { createRouter, createWebHistory, Route } from 'vue-router'; const router = createRouter({ history: createWebHistory(), routes: [] }); router.beforeEach((to: Route, from: Route, next) => { // 可以检查to和from的属性,例如to.name, from.path等 if (to.name === 'protectedRoute' &&!isAuthenticated()) { next('/login'); } else { next(); } }); const isAuthenticated = (): boolean => { // 模拟认证检查 return true; };
- 在使用
- 组件内守卫:
- 在组件内使用
beforeRouteEnter
、beforeRouteUpdate
和beforeRouteLeave
等守卫时,to
和from
参数同样是Route
类型。例如,在组件中:
import { defineComponent } from 'vue'; import { Route } from 'vue-router'; export default defineComponent({ beforeRouteEnter(to: Route, from: Route, next) { if (to.query.redirect) { // 处理重定向逻辑 next(to.query.redirect as string); } else { next(); } } });
- 在组件内使用
- 路由元信息类型检查:
- 可以在路由配置中定义元信息(
meta
),并对其进行类型检查。例如,假设要定义一个需要认证的路由:
// 定义元信息类型 interface RouteMeta { requiresAuth: boolean; } const router = createRouter({ history: createWebHistory(), routes: [ { path: '/protected', name: 'protectedRoute', component: () => import('./views/ProtectedView.vue'), meta: { requiresAuth: true } as RouteMeta } ] }); router.beforeEach((to: Route, from: Route, next) => { const { requiresAuth } = to.meta as RouteMeta; if (requiresAuth &&!isAuthenticated()) { next('/login'); } else { next(); } });
- 可以在路由配置中定义元信息(
通过以上方法,可以在Vue CLI插件扩展中,使用TypeScript集成Vuex和Vue Router时,有效地解决类型声明问题,提高代码的健壮性和可维护性。