Как установить тип для объекта состояния в pinia?
Я делаю шахматы и использую Vue 3 и TypeScript с Pinia для управления состоянием.
Я хочу сделать что-то вроде следующего:
export const useStore = defineStore("game", {
state: () => {
return {
moves: [],
gameBoard: getInitialBoard(),
playerTurn: PieceColor.White,
previousPieceSelected: undefined
}
},
updatePreviousPieceSelected(piece: Piece | undefined ) {
this.previousPieceSelected = piece
}
}
})
UpdateGameState.vue
setup() {
const store = useStore()
const previousPieceSelected: Piece | undefined = store.previousPieceSelected;
let playerTurn: PieceColor = store.playerTurn;
const initialGameState: GameState = {
boardState: store.gameBoard,
playerTurn,
};
const updateGameState = (
cellRow: number,
cellCol: number,
currentPiece: Piece
) => {
if (
previousPieceSelected === undefined ||
previousPieceSelected.pieceType === PieceType.None
) {
store.updatePreviousPieceSelected(currentPiece);
}
if (
(previousPieceSelected !== currentPiece && (currentPiece.pieceType === PieceType.None || currentPiece.color !== previousPieceSelected.color))
) {
MovePiece(store.gameBoard, previousPieceSelected, {row: cellRow, col: cellCol} as Position)
store.updatePreviousPieceSelected(undefined);
store.changePlayer();
}
};
Однако я получаю сообщение об ошибке в следующей строке:
store.updatePreviousPieceSelected(currentPiece);
Этот currentPiece (типа Piece) не может быть назначен типу undefined. Я нашел способ заставить это работать, выполнив в моем магазине следующее:
export const useStore = defineStore("game", {
state: () => {
return {
moves: [],
gameBoard: getInitialBoard(),
playerTurn: PieceColor.White,
previousPieceSelected: getInitialPreviousPieceSelected()
}
},
actions: {
changePlayer() {
this.playerTurn =
this.playerTurn === PieceColor.White
? PieceColor.Black
: PieceColor.White;
},
updatePreviousPieceSelected(piece: Piece | undefined ) {
this.previousPieceSelected = piece
}
}
})
function getInitialPreviousPieceSelected(): Piece | undefined {
return undefined;
}
Но это чувствуется клуджем. Есть ли другой способ ввести previousPieceSelected в возвращаемое исходное состояние?
6 ответов
Тип
this.previousPieceSelected
выводится из начального состояния, и в настоящее время он инициализирован, поэтому он имеет тип (что означает, что ему может быть присвоено только значение).
Используйте утверждение типа в начальном
undefined
значение (т. е.as
ключевое слово плюс желаемый типPiece | undefined
).Также обратите внимание, что необязательные параметры могут быть указаны с помощью
?:
вместо того| undefined
. Это просто более простой способ его написания.
export const useStore = defineStore("game", {
state: () => {
return {
moves: [],
previousPieceSelected: undefined as Piece | undefined, 1️⃣
}
},
actions: { 2️⃣
updatePreviousPieceSelected(piece ?: Piece) {
this.previousPieceSelected = piece
}
}
})
или просто так
interface IUserState {
user: null | IUser
}
export const useUserStore = defineStore({
id: 'user',
state: (): IUserState => ({
user: null,
})
...
defineStore
— это общая функция в TypeScript, которая принимает два аргумента: идентификатор хранилища и состояние.
/**
* Creates a `useStore` function that retrieves the store instance
*
* @param id - id of the store (must be unique)
* @param options - options to define the store
*/
export declare function defineStore<Id extends string, S extends StateTree = {}, G extends _GettersTree<S> = {}, A = {}>(id: Id, options: Omit<DefineStoreOptions<Id, S, G, A>, 'id'>): StoreDefinition<Id, S, G, A>;
Таким образом, можно определить полностью типизированный
State
и название магазина.
import { defineStore } from 'pinia';
interface State {
borks: string[];
isWoof: boolean;
}
interface Getters {}
interface Actions {
addBork(bork: string) => void;
}
const useBorkStore = defineStore<'bork', State, Getters, Actions>('bork', {
state: () => {
return {
borks: [],
isWoof: false
}
},
actions: {
addBork(bork: string) {
this.borks.push(bork);
}
}
})
export { useBorkStore };
Если данные не загружены.
Попробуйте: https://pinia.vuejs.org/core-concepts/state.html#typescript
другой:
import {defineStore} from 'pinia'
interface Menu {
path: string
name: string
component: string
meta: {
title: string
icon: string
affix?: string
}
}
const useAppStore = defineStore('app', {
state: () => ({
state: <boolean>false, // boolean
message: <string>'msg', // string
tagsView: <Menu[]>[] // array
})
})
export default useAppStore
Например:
type UserState = {
login: string
isPremium: boolean
}
const useUserStore = defineStore<string, UserState>('user', {
state: () => ({
login: 'test',
isPremium: false,
}),
})
Где
getInitialBoard()
приходящий из? Это импорт? ваши инициализированные данные не должны быть вашими вычисленными значениями. Это больше функция «добытчиков» в пинии. У вас есть «состояние», «геттеры» и «действия». Состояние обычно представляет собой инициализированные типизированные переменные. Геттеры — это вычисляемые возвращаемые значения без изменения данных состояния. Действия изменяют данные состояния. Вы должны изменять данные состояния только с помощью действий сохранения, а не внутри экземпляра компонента вне pinia. Все данные, источник правды, все время остаются в пинии. Держите свои магазины организованными таким образом:
// conceptual model e.g.
pinia {
state: () => {
return { data }
},
getters: {
// doesn't change data
getter: (state) => state.data.returnComputedState(),
},
actions: {
// changes data
action: () => this.data = mutateTheData(this.data),
},
}