介绍
我负责 Vue3 x Pinia x TypeScript 项目。
写单个组件文件的方法介绍composition api已经有一段时间了,所以很容易写很多信息。
我很难过,因为日语中几乎没有对使用 Pinia 有帮助的信息。
这次记录一下使用Pania时类型定义的方法。希望对以后介绍Pinia的人有所帮助。
我也发过一篇文章总结了单个组件的打法,请参考
https://qiita.com/manzoku_bukuro/items/a2dd20e787617b033592
商店符号
在输入之前,请检查 Pinia Store 文件描述方法。至于 Pinia 的 Store 文件的描述方法,类似 API 的写作风格什么时候如何编写类似 Options API有。
组合API样式描述方法
描述如下。
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
return { count, doubleCount, increment };
})
- 状态是使用 Composition API ref,reactive 定义的
- 使用计算定义的吸气剂
- 使用函数定义操作
- 返回已定义状态、getter 和操作的内容,最后以 return
符号特征如下。您不必描述状态、getter 和操作等属性,因此您可以用简洁的方式编写它。
但是,在我看来,它太干净了,很难区分状态、getter 和 action……(尤其是 getter 和 action)
并且为了使用使用DefineStoreOptions
的类型定义方式,后面会讲到,我参与的项目写了一个Options API风格。
选项 API 样式说明
import { defineStore } from 'pinia';
export const useCounterStore = defineStore({
id: 'counter',
state: () => ({
counter: 1,
}),
getters: {
doubleCount: (state) => return state.counter * 2;
},
actions: {
const increment = () => {
count.value++;
};
},
})
我将上面的源代码重写为 Options API 样式。除了定义id的部分,写法和Vuex是一样的,所以我想很多人会觉得这个比较容易理解。松树官方文件即使你看,我也觉得基础知识是在 Options API 风格中描述的。
从现在开始,我们将使用 Options API 样式描述方法来描述类型定义的方法。
如何在 Pinia 中定义类型
在 Store 中定义类型有几种方法,所以我将描述我所知道的方法。
我们将在 store 目录下键入未在下面定义类型的文件。
初始存储文件
import { defineStore } from "pinia";
export const useExampleStore = defineStore({
id: 'example',
state: () => ({
name: '田中太郎',
sales: 0,
menus: ['ホーム', '一覧'],
book: { title: '人間失格', price: 1070 },
}),
getters: {
introduction: (state) => {
return `私の名前は${state.name}です。`;
},
bookPrice: (state) => {
return state.book.price * 1.08;
},
},
actions: {
changeName(name) {
this.name = name;
},
buyBook(count) {
this.sales = this.bookPrice * count;
return `現在の売上は${this.sales}です。`
}
},
})
模式 1. 一个一个地定义状态变量
使用类型断言as
此模式是在 State 中的每个变量之后使用 as
定义的。
import { defineStore } from "pinia";
export interface Book {
title: string;
price: number;
}
export const useExampleStore = defineStore({
id: 'example',
state: () => ({
name: '田中太郎' as string,
sales: 0 as number,
menus: ['ホーム', '一覧'] as string[],
book: { title: '人間失格', price: 1070 } as Book,
}),
...
})
模式2. 统一定义State变量的类型
用as
定义State属性变量定义的对象
一种包装和键入 state 属性的方法,而不是在每个变量之后键入。
state: () => ({
name: '田中太郎',
sales: 0,
menus: ['ホーム', '一覧'],
book: { title: '人間失格', price: 1070 },
} as {
name: string,
sales: number,
menus: string[],
book: Book,
}),
这很好,但我认为如果将 state 中定义的类型包装在接口中会更容易理解。
...
export interface exampleState {
name: string;
sales: number;
menus: string[];
book: Book;
}
export const useExampleStore = defineStore({
id: 'example',
state: () => ({
name: '田中太郎',
sales: 0,
menus: ['ホーム', '一覧'],
book: { title: '人間失格', price: 1070 },
} as exampleState),
)}
在 State 中传递()
后面键入的对象
它是一种在状态后面传递类型定义对象的方法,如下所示。在以下情况下,对象被包装在接口中并传递。
export interface exampleState {
name: string;
sales: number;
menus: string[];
book: Book;
}
export const useExampleStore = defineStore({
id: 'example',
state: (): exampleState => ({
name: '田中太郎',
sales: 0,
menus: ['ホーム', '一覧'],
book: { title: '人間失格', price: 1070 },
}),
)}
(重要!!)模式 3. 使用 DefineStoreOptions 类型定义 State、Getters 和 Actions
也许本文中最有用的信息是如何定义类型。
定义存储()可选参数使用功能。您可以通过在defineStore 的头部传递Id、State、GTters、Actions 的类型定义参数来省略defineStore() 中的类型定义。
即使你在网上搜索,也很少有使用DefineStoreOptions定义类型的信息,Pinia 官方文档被翻译成日文并作为参考实施。下面是源码。
import { defineStore, type _GettersTree } from "pinia";
export interface Book {
title: string;
price: number;
}
export interface exampleState {
name: string;
sales: number;
menus: string[];
book: Book;
}
export interface exampleGetters extends _GettersTree<exampleState> {
introduction: (state: exampleState) => string;
bookPrice: (state: exampleState) => number;
}
export interface exampleActions {
changeName: (name: string) => void;
buyBook: (count: number) => string;
}
export const useSampleStore = defineStore<string, exampleState, exampleGetters, exampleActions>({
id: 'example',
state: () => ({
name: '田中太郎',
sales: 0,
menus: ['ホーム', '一覧'],
book: { title: '人間失格', price: 1070 },
}),
getters: {
introduction: (state) => {
return `私の名前は${state.name}です。`;
},
bookPrice: (state) => {
return state.book.price * 1.08;
},
},
actions: {
changeName(name) {
this.name = name;
},
buyBook(count) {
this.sales = this.bookPrice * count;
return `現在の売上は${this.sales}です。`
}
},
})
以defineStore<Id, S, G, A>
的形式传递类型
ExampleState、exampleGetters 和 exampleActions 都用接口定义,并在 defineStore 的头部传递,如defineStore<string(idの型), exampleState(stateの型), exampleGetters(gettersの型), exampleActions(actionsの型)>
。这样就不需要在defineStore里面描述类型定义了,源代码也变得更干净了。
使用_GettersTree
当我定义exampleGetters(gettersの型)
时,我最初写道:
export interface exampleGetters {
introduction: (state: exampleState) => string
bookPrice: (state: exampleState) => number
}
但是,以下错误消息按原样显示。
嗯,getters 属性参数状态的输入方式似乎有问题。
状态在 getter 中定义的属性的参数中定义。这个状态也是需要打字的,但是需要使用稍微特殊的描述方式。
export interface exampleGetters extends _GettersTree<exampleState> {
introduction: (state: exampleState) => string;
bookPrice: (state: exampleState) => number;
}
如上图,需要继承_GettersTree<Stateの型>
形式定义的State类型。错误现在消失了。
为未使用的属性传递空对象
如果您想在未定义 getter 或操作时使用 DefineStoreOptions,只需将一个空对象作为您不想使用的属性的参数传递。
export const useSampleStore = defineStore<string, {}, {}, {}>({
id: 'example',
state: () => ({}),
getters: {},
actions: {},
})
综上所述
在主项目中实际使用的 Pinia 的类型定义方法是使用 Pattern 3 DefineStoreOptions 的方法。不需要在里面写杂乱无章的类型化描述,源代码也变得很容易理解是在做什么样的处理。
但是,如果只有一个变量来定义 State,或者如果您正在处理一个既没有定义 Getters 也没有定义 Actions 的 Store 文件,使用 DefineStoreOptions 将使无用的部分突出,因此您可以使用 Pattern 1 或 Pattern 定义类型2. 做了。
请随时根据需要使用它。
推特我也在做
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308633157.html