如何在没有类样式或decorator语法的情况下获得MapGetter、mapActions Vuex和typescript的智能感知

如何在没有类样式或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

我使用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[]
}

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尝试了它