forked from vuejs/vuex
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Amirzhan Aliyev
committed
Dec 18, 2022
1 parent
c824cd9
commit 2c454d2
Showing
1 changed file
with
133 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
# Поддержка TypeScript | ||
|
||
Vuex предоставляет типизацию, поэтому можно использовать TypeScript при создании хранилища. Специальная конфигурация не требуется. Пожалуйста, следуйте [Базовой настройке TypeScript в Vue](https://v3.ru.vuejs.org/ru/guide/typescript-support.html), чтобы настроить проект. | ||
|
||
Однако, если писать компоненты Vue на TypeScript, то нужно выполнить несколько шагов, которые потребуют правильного обеспечения типов для хранилища. | ||
|
||
## Типизация `$store` свойства в Vue компоненте | ||
|
||
Vuex не предоставляет типизацию для свойства `this.$store` из коробки. При использовании с TypeScript, необходимо объявить собственный модуль расширения. | ||
|
||
Для этого объявляем пользовательскую типизацию для Vue `ComponentCustomProperties`, добавив файл деклараций в каталог вашего проекта: | ||
|
||
```ts | ||
// vuex.d.ts | ||
import { Store } from 'vuex' | ||
|
||
declare module '@vue/runtime-core' { | ||
// объявляем собственные состояния хранилища | ||
interface State { | ||
count: number | ||
} | ||
|
||
// указываем типизацию для `this.$store` | ||
interface ComponentCustomProperties { | ||
$store: Store<State> | ||
} | ||
} | ||
``` | ||
|
||
## Типизация функции композиции `useStore` | ||
|
||
При создании компонента Vue в стиле Composition API, скорее всего захочется, чтобы `useStore` возвращал типизированное хранилище. Чтобы `useStore` правильно возвращал типизированное хранилище, теперь необходимо: | ||
|
||
1. Определить типизированный `InjectionKey`. | ||
2. Указать типизированный `InjectionKey` при установке хранилища в приложение Vue. | ||
3. Передать типизированный `InjectionKey` методу `useStore`. | ||
|
||
Давайте разбираться с этим шаг за шагом. Во-первых, определяем ключ используя Vue интерфейс `InjectionKey` вместе с собственным определением типизации хранилища: | ||
|
||
```ts | ||
// store.ts | ||
import { InjectionKey } from 'vue' | ||
import { createStore, Store } from 'vuex' | ||
|
||
// определяем типизацию для состояния хранилища | ||
export interface State { | ||
count: number | ||
} | ||
|
||
// определяем ключ внедрения | ||
export const key: InjectionKey<Store<State>> = Symbol() | ||
|
||
export const store = createStore<State>({ | ||
state: { | ||
count: 0 | ||
} | ||
}) | ||
``` | ||
|
||
Затем передаём определённый ключ внедрения при установке хранилища в Vue приложение: | ||
|
||
```ts | ||
// main.ts | ||
import { createApp } from 'vue' | ||
import { store, key } from './store' | ||
|
||
const app = createApp({ ... }) | ||
|
||
// передаём ключ внедрения | ||
app.use(store, key) | ||
|
||
app.mount('#app') | ||
``` | ||
|
||
В заключение, можно передать ключ методу `useStore` для получения типизированного хранилища. | ||
|
||
```ts | ||
// в vue компоненте | ||
import { useStore } from 'vuex' | ||
import { key } from './store' | ||
|
||
export default { | ||
setup () { | ||
const store = useStore(key) | ||
|
||
store.state.count // типизировано как число | ||
} | ||
} | ||
``` | ||
|
||
Под капотом Vuex устанавливает хранилище в приложение Vue, используя функции Vue [Provide/Inject](https://v3.ru.vuejs.org/ru/api/composition-api.html#provide-inject) поэтому ключ внедрения важный фактор. | ||
|
||
### Упрощение использования `useStore` | ||
|
||
Необходимость импортировать `InjectionKey` и передавать его в `useStore` везде, где он используется, может быстро превратиться в повторяющуюся задачу. Чтобы упростить задачу, определяем собственную функцию композиции для получения типизированного хранилища: | ||
|
||
```ts | ||
// store.ts | ||
import { InjectionKey } from 'vue' | ||
import { createStore, useStore as baseUseStore, Store } from 'vuex' | ||
|
||
export interface State { | ||
count: number | ||
} | ||
|
||
export const key: InjectionKey<Store<State>> = Symbol() | ||
|
||
export const store = createStore<State>({ | ||
state: { | ||
count: 0 | ||
} | ||
}) | ||
|
||
// определяем собственную функцию композиции `useStore` | ||
export function useStore () { | ||
return baseUseStore(key) | ||
} | ||
``` | ||
|
||
Теперь, импортировав собственную функцию композиции, можно получить типизированное хранилище **без необходимости** предоставления ключа внедрения и его типизации: | ||
|
||
```ts | ||
// в vue компоненте | ||
import { useStore } from './store' | ||
|
||
export default { | ||
setup () { | ||
const store = useStore() | ||
|
||
store.state.count // типизировано как число | ||
} | ||
} | ||
``` |