สวัสดี ฉันชอบแนวคิดของ vuex และมีร้านค้าระดับโลก แต่ฉันเกลียดการใช้การกลายพันธุ์โดยส่ง magic-string ไปยังฟังก์ชัน commit เสมอ วิธีแก้ปัญหานี้แค่ขอให้พิมพ์ผิด ดังนั้น เมื่อ typescript ได้รับความนิยม ฉันตื่นเต้นมากที่อาจมีคนแก้ไขการกลายพันธุ์ของ 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) และรับการเติมโค้ดที่ยอดเยี่ยมของ typescript ทุกที่โดยไม่ต้องใช้ magic-strings ที่ใดก็ได้

ตกลง ดังนั้นเราจึงจัดการกับการกลายพันธุ์ของเราด้วยวิธีที่ดี แต่แล้ว getters ล่ะ?

คอมโพเนนต์ Class Bassed Vue ที่เขียนด้วย typescript บังคับให้คุณใช้ไวยากรณ์นี้:

@Getter clients!: Array<Client>;

และอีกครั้งก็ไม่ได้แย่นัก แต่สมมติว่าคุณต้องการฟอร์แมตตัวแปรไคลเอนต์ของคุณใหม่ คุณต้องจำไว้ว่าต้องเปลี่ยนชื่อเหล่านี้ทุกที่และมันก็ยุ่งมาก

กลับไปที่ห้องสมุด vuex-typescript ของเรากัน เช่นเดียวกับ commit it ที่มีฟังก์ชัน 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 service typescript getter ของฉันด้วยการสนับสนุน typescript แบบเต็มและเขียน getter ที่พิมพ์เต็มของฉันดังนี้:

get getClients() {
  return this.read<Array<Client>>(ClientStoreModule.getters.clients)
}

เพียงเท่านี้ เรามี getters ที่พิมพ์เต็มและการกลายพันธุ์ที่พิมพ์เต็มในบริการ ClientStore ของเรา และเราสามารถเข้าถึง vuex getters ของเราได้ดังนี้:
ClientStore.getClients()