Типизация stores

Quasar Framework предоставляет гибкую систему управления состоянием через Vuex или Composition API с использованием pinia. Типизация stores является ключевым элементом при разработке сложных приложений, поскольку она обеспечивает безопасность типов, автодополнение и предотвращает ошибки на этапе компиляции. Рассмотрим детально подходы к типизации stores и практические рекомендации.


Типизация Vuex Store

В Quasar с Vue 2/3 часто используется Vuex. Основная цель — определить структуру состояния, геттеров, мутаций и экшенов.

1. Типизация состояния

interface UserState {
  id: number;
  name: string;
  email: string;
  isLoggedIn: boolean;
}

const state: UserState = {
  id: 0,
  name: '',
  email: '',
  isLoggedIn: false
};
  • Интерфейс UserState задаёт строгую структуру состояния.
  • Типизация состояния позволяет получить автодополнение при работе с state в геттерах и компонентах.

2. Типизация мутаций

import { MutationTree } from 'vuex';

const mutations: MutationTree<UserState> = {
  setUser(state, payload: { id: number; name: string; email: string }) {
    state.id = payload.id;
    state.name = payload.name;
    state.email = payload.email;
    state.isLoggedIn = true;
  },
  logout(state) {
    state.id = 0;
    state.name = '';
    state.email = '';
    state.isLoggedIn = false;
  }
};
  • Использование MutationTree<UserState> гарантирует, что все мутации соответствуют типу состояния.
  • Мутации принимают строго типизированный payload, что предотвращает передачу неверных данных.

3. Типизация геттеров

import { GetterTree } from 'vuex';

const getters: GetterTree<UserState, any> = {
  userName: (state) => state.name,
  isAuthenticated: (state) => state.isLoggedIn
};
  • GetterTree<UserState, RootState> обеспечивает строгую проверку возвращаемых типов.
  • Рекомендуется явно указывать тип возвращаемого значения для сложных геттеров.

4. Типизация экшенов

import { ActionTree } from 'vuex';

const actions: ActionTree<UserState, any> = {
  login({ commit }, payload: { id: number; name: string; email: string }) {
    commit('setUser', payload);
  },
  logout({ commit }) {
    commit('logout');
  }
};
  • Экшены типизируются через ActionTree<State, RootState>.
  • Параметры контекста и payload строго типизированы, что уменьшает вероятность ошибок.

Типизация Store с Pinia

Pinia — современная альтернатива Vuex, которая встроена в Quasar с Vue 3. Она поддерживает полную интеграцию TypeScript без дополнительной сложности.

1. Создание типизированного store

import { defineStore } from 'pinia';

interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

interface TodoState {
  todos: Todo[];
}

export const useTodoStore = defineStore('todo', {
  state: (): TodoState => ({
    todos: []
  }),
  getters: {
    completedTodos: (state) => state.todos.filter(todo => todo.completed)
  },
  actions: {
    addTodo(todo: Todo) {
      this.todos.push(todo);
    },
    toggleTodo(id: number) {
      const todo = this.todos.find(t => t.id === id);
      if (todo) todo.completed = !todo.completed;
    }
  }
});
  • Интерфейсы Todo и TodoState задают строгую структуру данных.
  • Автодополнение работает для state, getters и actions.
  • Методы actions автоматически получают правильные типы для this.

2. Типизация с Composition API

import { ref, computed } from 'vue';
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', () => {
  const count = ref<number>(0);
  const double = computed(() => count.value * 2);

  function increment(amount: number) {
    count.value += amount;
  }

  return { count, double, increment };
});
  • Использование ref<number> и computed позволяет явно указать тип состояния.
  • Типизация функций increment гарантирует, что передаваемые значения всегда соответствуют ожидаемому типу.

Рекомендации по типизации

  1. Всегда использовать интерфейсы для состояния. Это облегчает поддержку и масштабирование приложения.
  2. Явно типизировать payload мутаций и экшенов. Избегает runtime ошибок.
  3. Использовать defineStore с Pinia в новых проектах. Типизация встроена и проще в поддержке.
  4. Типизация геттеров и computed обеспечивает автодополнение и предотвращает ошибки при доступе к сложным структурам.
  5. Сохранять согласованность типов между состоянием, мутациями, экшенами и компонентами.

Примеры интеграции с компонентами

import { useTodoStore } from 'stores/todo';

export default {
  setup() {
    const todoStore = useTodoStore();

    function addNewTodo() {
      todoStore.addTodo({ id: 1, title: 'Learn Quasar', completed: false });
    }

    return { todoStore, addNewTodo };
  }
};
  • Типизированный store гарантирует, что todoStore.addTodo принимает объект строго типа Todo.
  • Автодополнение помогает сразу видеть доступные геттеры и actions.

Типизация stores в Quasar является основой для устойчивых, масштабируемых и безопасных приложений, обеспечивая строгую проверку типов на каждом уровне управления состоянием.