Привет, мне очень нравится идея vuex и глобального хранилища, но я всегда ненавидел использовать мутации, передавая magic-string
функции фиксации. Это решение просто напрашивается на опечатку. Поэтому, когда машинописный текст стал популярным, я был очень взволнован тем, что, возможно, кто-то исправит мутации Vuex, чтобы вам не нужно было использовать magic-strings
, но, к сожалению, этого не произошло: /
Я решил поставить себе цель создать сервис магазина с действиями, основанными на полностью типизированных мутациях. Итак, я создал простой модуль vuex, который выглядит так:
export const ClientStoreModule = { namespaced: false, state: new ClientStoreState(), getters: { clients(state: ClientStoreState) { return state.Clients; }, }, mutations: { setClients(state: ClientStoreState, clients: Array<Client>) { state.Clients = clients; }, addClient(state: ClientStoreState, client: Client) { state.Clients.push(client); }, }, };
А вот и мой государственный класс:
export class ClientStoreState { Clients: Array<Client> = []; }
Моей целью было добиться мутаций, которые можно было бы использовать примерно так:
commit<Client>(ClientStoreModule.mutations.addClient, client);
Итак, я начал с Google эту проблему и нашел отличную библиотеку под названием vuex-typescript
, и вот ссылка:
Это классная библиотека, но она заставила вас использовать такие коммиты:
let storeApi = getStoreAccessors<ClientStoreState, RootState>('') let commit = storeApi.commit(ClientStoreModule.mutations.addClient) commit(this.$store, client)
Для получения полной документации перейдите по ссылке, которую я разместил выше.
И снова, ладно, это круче, чем старомодно commit('addClient', client)
. Теперь у нас есть полностью типизированные мутации! Но это решение длинное, и для его использования требуется много кода. Так что я немного завернул его.
Я создал абстрактный класс, чтобы расширить свой будущий сервис с помощью действий vuex:
import {getStoreAccessors, MutationHandlerWithPayload} from 'vuex-typescript'; export default abstract class BaseStoreService<T> { protected mutations!: Record<string,(state: T, payload: any) => void>; protected storeApi = getStoreAccessors<T, RootState>(''); protected commit<TPayload>(handler: (MutationHandlerWithPayload<T, TPayload>), payload: TPayload) { this.storeApi.commit(handler)(store, payload); } }
Я использую модули vuex, поэтому мой RootState - это просто интерфейс всего моего магазина vuex.
Хорошо, теперь пора создать службу vuex моей мечты, которая обрабатывает действия:
class ClientStore extends BaseStoreService<ClientStoreState> { public mutations = ClientStoreModule.mutations; async addClient(newClient: Client) { this.commit<Client>(this.mutations.addClient, newClient); } async fetchClients(clients) { this.commit(this.mutations.setClients, clients); } } export default new ClientStore();
И вот, теперь мы можем использовать нашу полностью типизированную службу с полностью типизированными мутациями, подобными этой ClientStore.addClient(client)
, и получить отличное автозавершение кода машинописного текста везде, не используя magic-strings
где бы то ни было.
Итак, мы хорошо обрабатываем наши мутации, но как насчет getters
?
Компонент vue на основе классов, написанный на машинописном тексте, заставляет вас использовать этот синтаксис:
@Getter clients!: Array<Client>;
И снова это не так уж и плохо, но допустим, вы хотите переформатировать переменную клиентов. Вы должны не забывать менять эти имена везде, и это просто беспорядок.
Вернемся в нашу vuex-typescript
библиотеку. Так же, как commit
, у него есть read
функция. Итак, я расширил свой BaseStoreService
второй функцией:
import {getStoreAccessors, GetterHandler, MutationHandlerNoPayload, MutationHandlerWithPayload} from 'vuex-typescript'; export default abstract class BaseStoreService<T> { protected mutations!: Record<string,(state: T, payload: any) => void>; protected storeApi = getStoreAccessors<T, RootState>(''); protected commit<TPayload>(handler: (MutationHandlerWithPayload<T, TPayload>), payload: TPayload) { this.storeApi.commit(handler)(store, payload); } protected read<TResult>(handler: GetterHandler<T, RootState, TResult>): TResult { return this.storeApi.read<TResult>(handler)(store); } }
так что теперь я могу добавить в свой ClientStore
метод получения машинописного текста с полной поддержкой машинописного текста и написать свой полностью типизированный получатель следующим образом:
get getClients() { return this.read<Array<Client>>(ClientStoreModule.getters.clients) }
Вот и все, что у нас есть полностью типизированные геттеры и полностью типизированные мутации внутри нашей ClientStore
службы, и мы можем получить доступ к нашим геттерам vuex следующим образом: ClientStore.getClients()