클래스 스타일 또는 데코레이터 구문을 사용하지 않고 mapGetters, mapActions Vuex 및 typescript의 인텔리센스를 얻는 방법
한동안 Vue.js와 Vuex를 사용하지만 항상 javascript와 함께 사용합니다.
좀 더 구체적으로 말하면 Typescript, nuxt.js와 함께 Vue를 사용하려고 하는데 데코레이터나 style-class-component를 사용하지 않고 일반 Vue 구문만 계속합니다.
Vuex 스토어에 있는 코드입니다.
/store/todos/types.ts
export interface Todo {
id: number
text: string
done: boolean
}
export interface TodoState {
list: Todo[]
}
/store/todos/state.ts
import { TodoState } from './types'
export default (): TodoState => ({
list: [
{
id: 1,
text: 'first todo',
done: true
},
{
id: 2,
text: 'second todo',
done: false
}
]
})
/store/todos/mutations.ts
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>
/store/todos/actions.ts
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>
/store/todos/getters.ts
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>
이건 내 컴포넌트를 가지고 있는 코드야
<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>
Vuex에서 발생한 Getter 또는 액션의 자동 완료/인텔리센스 이외에는 모든 것이 완벽하게 동작합니다.
누가 날 도와줄까?
감사합니다.
Vuex는 현재 형식에서 Typescript와 함께 사용할 수 없습니다.Vue 3에서는 이 점이 변경될 수 있습니다.
@Component
장식가들, 특히 그들이 비천해졌기 때문에.그러나 기본 Vue 유형 스크립트 구성 요소 스타일을 사용하는 경우:
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({...})
</script>
...여러 솔루션을 테스트한 결과, 가장 사용하기 쉬운 것은 실제로 데코레이터를 사용하는 플러그인이라는 것을 알게 되었습니다.vuex-module-decorators
Vuex 모듈:
일반적으로 부모 상태를 클린(빈) 상태로 두고 nameshorized 모듈을 사용합니다.저는 주로 프로젝트의 마지막에 여러 개의 모듈을 설치하는 것이 더 깨끗하고 단순히 추가 모듈을 만드는 것보다 상위 모듈에서 모듈로 이동하는 것이 더 번거롭기 때문에 이 작업을 수행합니다.
스토어는 다음과 같습니다.
import Vue from 'vue';
import Vuex from 'vuex';
import { getModule } from 'vuex-module-decorators';
import Whatever from '@/store/whatever';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
whatever: Whatever
}
});
getModule(Whatever, store); // this is important for typescript to work properly
export type State = typeof store.state;
export default store;
다음은 의 몇 가지 예를 제시하겠습니다.mapState
,mapGetters
get/set:
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
can can can can a a a a a a a a a a a a a a a a a a a a로 사용할 수 있게 되었습니다.v-model
.메모mapGetters
.
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 }
}
}
그럼 이제, 이, 이, 이, 이, 이, 이, 이, 이, now, now, now, now, now, now, now, now, now, now, now, now, now, now, now, now, now, now@Action
★★★★★★★★★★★★★★★★★」@Mutation
데코레이터는 그만 두셔도 됩니다. 이치노제가 것들을 사용하고 자신을 발견했어요.@MutationAction
이치노해킹을 원하신다면요.
의 내부@MutationAction
,this
모듈 클래스가 아닙니다.액션 컨텍스트(JS Vuex)
interface ActionContext<S, R> {
dispatch: Dispatch;
commit: Commit;
state: S;
getters: any;
rootState: R;
rootGetters: any;
}
그리고 그건 문제가 아니야.가 Typescript라고 생각한다는 입니다.this
가 '모듈 클래스' 안에 ?@MutationAction
여기서부터 캐스팅을 시작하거나 타이프가드를 사용할 필요가 있습니다..any
. 타이프가드는 멀리 갈 수 있다.
황금률이란 '만약 내가 캐스팅을 해야 한다면'as any
또는as unknown as SomeType
를 분할해야 한다는 것은 분명한 신호입니다.@MutationAction
으로@Action
및 a@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
는 로 등록됩니다.@Action
s, 그들은 s를 가져간다.{ mutate: [/* full list of props to be mutated*/]}
그리고 변이될 소품 배열에 선언된 모든 국가 소품을 가진 물체를 반환한다.
이상입니다.
* 주의 1: 동일한 2개의 다른 입력(일반 입력과 슬라이더 입력)을 사용할 때 이 체크를 사용해야 합니다.get/set
v-model
그 체크가 없다면, 각각의 체크가set
스택 스위칭에러가 발생합니다.입력이 1개뿐일 때는 보통 체크가 필요하지 않습니다.
* 주의 2: 내 방법은 다음과 같습니다.main.ts
으로 닮다
import ...
Vue.use(...);
Vue.config...
const Instance = new Vue({
...
}).$mount(App);
// anything I might want to import in components, store modules or tests:
export { $store, $t, $http, $bus } = Instance;
/* I'd say I use these imports more for correct typing than for anything else
(since they're already available on `this` in any component). But they're
quite useful outside of components (in services, helpers, store, translation
files, tests, etc...)
*/
이 문제에 대한 해결책을 찾다가 이 질문을 발견했습니다.실험을 좀 해봤는데 해결책이 있을 것 같아요.
이라고 하는 은, 그 방법들을 입니다.mapGetters
★★★★★★★★★★★★★★★★★」mapActions
따라서 Typescript가 관련된 유형을 추론할 수 있습니다.매퍼에 잘못된 키를 입력하면 컴파일 시간 오류가 발생하며, 보너스로 반환 유형이 정확합니다(더 이상 없음).
// returns a type which skips the first context argument
type OmitActionContext<F> = F extends (
injectee: ActionContext<any, any>,
payload: infer P
) => infer R
? (payload?: P) => Promise<PromiseValue<R>>
: never;
// signature of action methods
type ActionMethod = (
injectee: ActionContext<any, any>,
...args: any[]
) => Promisable<any>;
/** Typed wrapper for mapActions using a namespaced store and renaming the keys
*
* NOTE: needs to be called with extra parenthesis to infer map keys correctly
*
* @example
* mapActionsNamespacedWithRename<TYPE>()(namespace, map)
*
*/
export const mapActionsNamespacedWithRename = <
S extends Record<keyof S & string, ActionMethod>,
Keys extends keyof S & string = keyof S & string
>() => {
function anonymous<Prop extends string, Mp extends Record<Prop, Keys>>(
namespace: string,
map: Mp
): {
[P in Keys as GetKeyByValue<Mp, P>]: OmitActionContext<S[P]>;
};
function anonymous<Prop extends string, Mp extends Record<Prop, Keys>>(
namespace: string,
map: Mp
) {
return mapActions(namespace, map);
}
return anonymous;
};
위의 래퍼를 사용하면 payload와 Promise 반환 유형을 올바르게 추론할 수 있습니다.
하다, 입력하다, 입력하다, 라고 하면 ./store/todos/actions.ts
과 같이
import { ActionContext } from 'vuex'
import { RootState, RootGetters } from '../types'
import { TodoState, Todo } from './types'
export type TodoActionMethods = {
delete: (injectee: ActionContext<TodoState, RootState>, payload: Todo) => void
}
export default {
delete({ commit }, payload): void {
const {id} = payload;
commit('remove', id)
}
} as ActionTreeTyped<
TodoState,
RootState,
TodoActionMethods,
TodoGetters,
RootGetters
>
컴포넌트에서는 위의 래퍼를 사용해야 합니다.추가된 추가 괄호 및 일반 유형에 주의하십시오.
methods: {
...mapActionsNamespacedWithRename<TodoActionMethods>()("todos", {
destroy: 'delete'
})
}
모듈 증설 없음 - 순수한 Typescript 마법!
완전한 솔루션에 대해서는, 다음의 요점을 참조해 주세요.
언급URL : https://stackoverflow.com/questions/62053067/how-to-get-intellisense-of-mapgetters-mapactions-vuex-and-typescript-without-cl
'programing' 카테고리의 다른 글
python에서 행별로 MySQL ResultSet을 가져오는 방법 (0) | 2022.10.26 |
---|---|
time_t는 어떤 원시 데이터 유형입니까? (0) | 2022.10.26 |
javascript 파일 이름 짓기 규칙은 무엇입니까? (0) | 2022.10.26 |
MySQL에서 Maria로의 이행DB (0) | 2022.10.26 |
JavaScript 개체의 크기를 가져오려면 어떻게 해야 합니까? (0) | 2022.10.26 |