如何在没有类样式或decorator语法的情况下获得MapGetter、mapActions Vuex和typescript的智能感知
我使用Vue.js和Vuex有一段时间了,但总是使用javascript 我试图将Vue与Typescript一起使用,更具体地说,是nuxt.js,但不使用装饰器或样式类组件,只使用正常的Vue语法 这是我在Vuex商店中的代码如何在没有类样式或decorator语法的情况下获得MapGetter、mapActions Vuex和typescript的智能感知,typescript,vue.js,vuex,nuxt.js,Typescript,Vue.js,Vuex,Nuxt.js,我使用Vue.js和Vuex有一段时间了,但总是使用javascript 我试图将Vue与Typescript一起使用,更具体地说,是nuxt.js,但不使用装饰器或样式类组件,只使用正常的Vue语法 这是我在Vuex商店中的代码 /store/todos/types.ts export interface Todo { id: number text: string done: boolean } export interface TodoState { list: Todo
/store/todos/types.ts
export interface Todo {
id: number
text: string
done: boolean
}
export interface TodoState {
list: Todo[]
}
import { TodoState } from './types'
export default (): TodoState => ({
list: [
{
id: 1,
text: 'first todo',
done: true
},
{
id: 2,
text: 'second todo',
done: false
}
]
})
import { MutationTree } from 'vuex'
import { TodoState, Todo } from './types'
export default {
remove(state, { id }: Todo) {
const index = state.list.findIndex((x) => x.id === id)
state.list.splice(index, 1)
}
} as MutationTree<TodoState>
import { ActionTree } from 'vuex'
import { RootState } from '../types'
import { TodoState, Todo } from './types'
export default {
delete({ commit }, { id }: Todo): void {
commit('remove', id)
}
} as ActionTree<TodoState, RootState>
import { GetterTree } from 'vuex'
import { RootState } from '../types'
import { TodoState, Todo } from './types'
export default {
list(state): Todo[] {
return state.list
}
} as GetterTree<TodoState, RootState>
/store/todos/state.ts
export interface Todo {
id: number
text: string
done: boolean
}
export interface TodoState {
list: Todo[]
}
import { TodoState } from './types'
export default (): TodoState => ({
list: [
{
id: 1,
text: 'first todo',
done: true
},
{
id: 2,
text: 'second todo',
done: false
}
]
})
import { MutationTree } from 'vuex'
import { TodoState, Todo } from './types'
export default {
remove(state, { id }: Todo) {
const index = state.list.findIndex((x) => x.id === id)
state.list.splice(index, 1)
}
} as MutationTree<TodoState>
import { ActionTree } from 'vuex'
import { RootState } from '../types'
import { TodoState, Todo } from './types'
export default {
delete({ commit }, { id }: Todo): void {
commit('remove', id)
}
} as ActionTree<TodoState, RootState>
import { GetterTree } from 'vuex'
import { RootState } from '../types'
import { TodoState, Todo } from './types'
export default {
list(state): Todo[] {
return state.list
}
} as GetterTree<TodoState, RootState>
/store/todos/translations.ts
export interface Todo {
id: number
text: string
done: boolean
}
export interface TodoState {
list: Todo[]
}
import { TodoState } from './types'
export default (): TodoState => ({
list: [
{
id: 1,
text: 'first todo',
done: true
},
{
id: 2,
text: 'second todo',
done: false
}
]
})
import { MutationTree } from 'vuex'
import { TodoState, Todo } from './types'
export default {
remove(state, { id }: Todo) {
const index = state.list.findIndex((x) => x.id === id)
state.list.splice(index, 1)
}
} as MutationTree<TodoState>
import { ActionTree } from 'vuex'
import { RootState } from '../types'
import { TodoState, Todo } from './types'
export default {
delete({ commit }, { id }: Todo): void {
commit('remove', id)
}
} as ActionTree<TodoState, RootState>
import { GetterTree } from 'vuex'
import { RootState } from '../types'
import { TodoState, Todo } from './types'
export default {
list(state): Todo[] {
return state.list
}
} as GetterTree<TodoState, RootState>
/store/todos/getters.ts
export interface Todo {
id: number
text: string
done: boolean
}
export interface TodoState {
list: Todo[]
}
import { TodoState } from './types'
export default (): TodoState => ({
list: [
{
id: 1,
text: 'first todo',
done: true
},
{
id: 2,
text: 'second todo',
done: false
}
]
})
import { MutationTree } from 'vuex'
import { TodoState, Todo } from './types'
export default {
remove(state, { id }: Todo) {
const index = state.list.findIndex((x) => x.id === id)
state.list.splice(index, 1)
}
} as MutationTree<TodoState>
import { ActionTree } from 'vuex'
import { RootState } from '../types'
import { TodoState, Todo } from './types'
export default {
delete({ commit }, { id }: Todo): void {
commit('remove', id)
}
} as ActionTree<TodoState, RootState>
import { GetterTree } from 'vuex'
import { RootState } from '../types'
import { TodoState, Todo } from './types'
export default {
list(state): Todo[] {
return state.list
}
} as GetterTree<TodoState, RootState>
从“vuex”导入{GetterTree}
从“../types”导入{RootState}
从“/types”导入{TodoState,Todo}
导出默认值{
列表(状态):待办事项[]{
返回状态列表
}
}as GetterTree
这是我的组件的代码
<template>
<div>
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
<button @click="destroy(todo)">delete</button>
</li>
</ul>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { mapGetters, mapActions } from 'vuex'
export default Vue.extend({
computed: {
...mapGetters({
todos: 'todos/list'
})
},
methods: {
...mapActions({
destroy: 'todos/delete'
})
}
})
</script>
-
{{todo.text}}
删除
从“Vue”导入Vue
从“vuex”导入{MapGetter,mapActions}
导出默认Vue.extend({
计算:{
…地图绘制者({
待办事项:“待办事项/清单”
})
},
方法:{
…映射操作({
销毁:“待办事项/删除”
})
}
})
除了来自Vuex的getter或操作的自动完成/智能感知之外,所有功能都可以完美运行
有人能帮我吗
感谢您的支持,在当前的形式下,Vuex不能很好地与Typescript配合使用。这可能会在VUE3中发生变化 和您一样,我也不想使用
@Component
装饰器,特别是因为它们已经被弃用了。但是,在使用默认的Vue typescript组件样式时:
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({...})
</script>
以下是直接与存储一起工作的mapState
、mapGetters
或get/set computed的几个示例:
computed: {
...mapGetters({
foo: 'whatever/foo',
bar: 'whatever/bar'
}),
...mapState({
prop1: (state: State): prop1Type[] => state.whatever.prop1,
prop2: (state: State): number | null => state.whatever.prop2
}),
// if i want get/set, for a v-model in template
baz: {
get: function(): number {
return this.$store.state.whatever.baz;
},
set: function(value: number) {
if (value !== this.baz) { // read * Note 1
this.$store.dispatch('whatever/setBaz', value);
// setBaz can be an `@Action` or a `@MutationAction`
}
}
}
}
baz
现在可以在v型中使用
。注意MapGetter
需要是实际的模块存储getter:
import { $http, $store } from '@/main'; // read * Note 2
import { Action, Module, Mutation, MutationAction, VuexModule } from 'vuex-module-decorators';
@Module({ namespaced: true, store: $store, name: 'whatever' })
export default class Whatever extends VuexModule {
get foo() {
return // something. `this` refers to class Whatever and it's typed
}
baz = 0;
prop1 = [] as prop1Type[]; // here you cast the type you'll get throughout the app
prop2 = null as null | number; // I tend not to mix types, but there are valid cases
// where `0` is to be treated differently than `null`, so...
@MutationAction({ mutate: ['baz'] })
async setBaz(baz: number) {
return { baz }
}
}
现在,使用@Action
或@Mutation
装饰器不会有任何问题,您可以到此为止,您不会有任何类型脚本问题。但是,因为我喜欢它们,我发现自己经常使用@MutationAction
s,尽管公平地说,它们是混合体。如果你愿意的话,可以用黑客。在
@MutationAction
中,此
不是模块类。这是一个ActionContext(基本上是正常js vuex操作中的第一个参数):
接口操作上下文{
调度:调度;
承诺:承诺;
国家:S;
获得者:任何;
根状态:R;
生根剂:任何;
}
这甚至不是问题所在。问题是Typescript认为这是@MutationAction
中的模块类。在这里,你需要开始铸造或使用护字板。一般来说,我会尽量减少施法次数,从不使用any
。打字护卫可以走很长的路。
黄金法则是:如果我需要将转换为任何类型的或转换为未知类型的,很明显,我应该将@MutationAction
分为@Action
和@Mutation
。但在绝大多数情况下,一个打字员就足够了。例如:
import { get } from 'lodash';
...
@Module({ namespaced: true, store: $store, name: 'whatever' })
export default class Whatever extends VuexModule {
@MutationAction({ mutate: ['someStateProp'] })
async someMutationAction() {
const boo = get(this, 'getters.boo'); // or `get(this, 'state.boo')`, etc...
if (boo instaceof Boo) {
// boo is properly typed inside a typeguard
// depending on what boo is, you could use other typeguards:
// `is`, `in`, `typeof`
}
}
如果只需要state
或getters
的值:this.state?.prop1 |【】
或this.getters?.foo
也可以工作
平心而论,@MutationAction
需要某种形式的类型攻击,因为您需要声明类型:它们不能正确推断。因此,如果您希望100%正确,请将它们的使用限制在您只需设置状态属性的值,并且不必同时写入操作和变量的情况下:
@MutationAction({ mutate: ['items'] })
async setItems(items: Item[]) {
return { items }
}
它取代了:
@Action
setItems(items: Item[]) {
this.context.commit('setItems', items);
// btw, if you want to call other @Action from here or any @MutationAction
// they work as `this.someAction();` or `this.someMutationAction()`;
}
@Mutation
setItems(items: Item[]) {
this.items = items;
}
@MutationAction
s注册为@Action
s,它们获取一个{mutate:[/*待突变的道具的完整列表*/]}
并返回一个对象,该对象具有在待突变的道具数组中声明的所有已声明状态道具
就这样
*注1:当我在同一get/set
v-model
上使用两个不同的输入(正常输入和滑块输入)时,我必须使用该检查。如果没有该检查,它们中的每一个在更新时都会触发集
,从而导致堆栈溢出错误。当您只有1个输入时,通常不需要该检查
*注2:下面是我的main.ts
的典型外观
导入。。。
Vue.使用(…);
Vue.config。。。
const实例=新的Vue({
...
})$mount(App);
//我可能希望在组件、存储模块或测试中导入的任何内容:
export{$store,$t,$http,$bus}=Instance;
/*我要说的是,我使用这些导入更多的是为了正确的输入,而不是其他任何东西
(因为它们已经在任何组件的“this”上可用)。但是他们是
在组件之外非常有用(在服务、助手、存储、翻译中
文件、测试等)
*/
哇,真管用!感谢您的回复,我甚至不知道如何感谢。我的最后一个问题是,您是否找到了不使用vuex模块装饰器的方法使其工作?我想以通常的方式编写Vuex模块,而不使用装饰程序。。。如果到目前为止最好的解决方案是与decorators一起使用,您能告诉我我可以将文件与模块分开吗?示例actions.ts
,getters.ts
,translations.ts
,state.ts
,如果是,您有如何执行此操作的示例吗?我有,但它们有限。你遇到了边缘案例。它们都可以解决,但您需要编写更多的代码(typeguard或casting)——这正是我想要避免的。我希望typescript推断类型,我不希望必须指定它们。关于分离获取者
,突变
,动作
和状态
,我还没有找到一种对类型脚本友好的方法。我们确实为一个更大的项目和af尝试了它